<?php
/**
 * Created by veema.
 * Function:竞赛相关方法类
 * Date: 20/8/10
 * Time: 9:42
 */

namespace app\api\controller;

use app\common\service\Exception;
use app\common\service\QueueService;
use think\Cache;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Error;
use think\exception\DbException;
use think\exception\ErrorException;
use think\Model;
use think\Request;
use app\admin\model\Device as DeviceModel;
use app\admin\model\DeviceSensor as DeviceSensorModel;
use think\Log;
use app\api\controller\Test;
use think\cache\driver\Redis as myRedis;
use think\response\Json;
use coordinate\Gps;

class Contest extends Base
{
    //存放船和坐标临时位置
    public $temp_location_data = [];
    public $temp_location_data_last = [];//上一次位置
    public $scope = 1000;//所有点判断范围，单位米
    public $temp_record = [];//船只绕点记录临时表
    public $temp_record_last = [];//上次船只绕点记录临时表
    public $temp_lines = [];//本次比赛路径数组
    public $temp_lines_idkey = [];//本次比赛路径数组-id作为key
    public $temp_boat_count = 0;//本次比赛所有选手数量，计算临时成绩用
    private $temp_all_distance = 0;//路径长度
    //------------------------------------------倒计时相关-------------------------------------------//
    private $temp_start_time = 0;//比赛开始倒计时时间
    private $temp_one_time = 0;//比赛开始倒计时到1分钟时间
    private $temp_zero_time = 0;//比赛倒计时为0时间
    private $temp_four_time = 0;//比赛倒计时结束到4分钟必须起航时间
    private $temp_countdown = 240;
    private $temp_all_countdown = 300;//倒计时
    private $time_now = 0;//现在时间
    private $temp_start_cross_points = [];//船只经过起始线时在起始线的点
    //------------------------------------------时限相关-------------------------------------------//
    public $match_zhong_limit = 0;//终点时限
    public $match_feng_limit = 0;//封闭时限()
    public $match_first_feng_limit = 0;//1标封闭时限
    public $match_start_limit = 0;//过启航线最晚时间
    public $match_zhong_flag = 0;//是否有船过了终点
    public $match_feng_limit_time = 0;//加上第一条船过了终点的封闭时限
    public $match_first_feng_flag = 0;//是否有船过了1标
    public $match_start_flag = 0;//是否有船过了启航线
    //------------------------------------------起航旗相关-------------------------------------------//
    public $match_flag_id = 0;//本场比赛起航旗id
    public $p_flag_id = 2;//p旗id
    public $i_flag_id = 3;//i旗id
    public $u_flag_id = 4;//u旗id
    public $b_flag_id = 5;//黑旗id
    public $z_flag_id = 6;//z旗id
    //--------------------
    public $redis;

    public function __construct()
    {
        $this->redis = new myRedis();
    }

    /**
     * 获取比赛下面所有的赛次
     * @param $match_id
     * @return
     */
    public function getMatchDetailsList()
    {
        try {
            $match_id = input('match_id');
            if (!$match_id) {
                return json(array('status' => 100, 'msg' => '参数不能为空'));
            }
            $detail_info = Db::table('up__match_detail d')
                ->join('up_match_group g', 'g.mg_id=d.level_id')
                ->where(['d.match_id' => $match_id])
//                ->where('d.flag', 'in',[1,3])
                ->field('d.id,d.match_id,d.turn,d.level_id,g.mg_name as level_name,d.start_time,d.end_time,d.flag')->select();
            return json(array('status' => 200, 'msg' => 'success', 'data' => $detail_info));
        } catch (\Exception $e) {
            return json(array('status' => 100, 'msg' => $e->getMessage()));
        }
    }

    /**
     * 获取回放初始化参数
     * @param $match_detail_id
     * @return
     */
    public function initPlayBack()
    {
        try {
            $match_detail_id = input('match_detail_id');
            if (!$match_detail_id) {
                return json(array('status' => 100, 'msg' => '参数不能为空'));
            }
            $detail_info         = $this->_match_detail_info($match_detail_id);
            $device_info         = $this->_getAllDevice(['match_detail_id' => $match_detail_id]);
            $data['match_info']  = $detail_info;
            $data['device_info'] = $device_info;

            $data['match_data'] = Db::table('up_match')->where('match_id', $detail_info['match_id'])->find();

            return json(array('status' => 200, 'msg' => 'success', 'data' => $data));
        } catch (\Exception $e) {
            return json(array('status' => 100, 'msg' => $e->getMessage()));
        }
    }

    /**
     * 获取比赛回访数据
     * @param $match_detail_id
     * @param $start
     * @param $scope
     * @return
     */
    public function getPlayBackDatas()
    {
        $match_detail_id = input('match_detail_id');
        $start           = input('start');
        $scope           = input('scope');
        if (empty($match_detail_id) || empty($start) || empty($scope)) {
            return json(array('status' => 100, 'msg' => '参数不能为空'));
        }
        $step_data      = Db::table('up__match_step')
            ->where(['match_detail_id' => $match_detail_id])
            ->where('time', '>=', $start)
            ->where('time', '<', ($start + $scope))
            ->field('time,data')
            ->select();
        $datas          = Db::table('up__match_datas')
            ->where(['match_detail_id' => $match_detail_id])
            ->where('time', '>=', $start)
            ->where('time', '<', ($start + $scope))
            ->field('time,data')
            ->select();
        $all_data       = [];
        $temp_datas     = [];
        $temp_step_data = [];
        foreach ($datas as $k => $v) {
            array_push($all_data, [
                'time'           => $v['time'],
                'calculate_data' => json_decode($v['data'], true),
                'locations_data' => json_decode($step_data[$k]['data'], true)
            ]);
        }

        foreach ($step_data as $k => $v) {
            $temp_step_data[$k][$v['time']] = json_decode($v['data'], true);
        }
        return json(array('status' => 200, 'msg' => 'success', 'data' => $all_data));
    }

    public function setit()
    {
        Db::table('up__match_detail')->where(['id' => 16])->update(['end_time' => 1597525579.1229]);
        sleep(2);
        Db::table('up__match_detail')->where(['id' => 16])->update(['end_time' => null]);
    }

    /**
     * 添加浮点设备
     * @param $app_sb_id
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function addDevice()
    {
        $app_sb_id = input('app_sb_id');
        if (empty($app_sb_id)) {
            return json(array('status' => 100, 'msg' => '设备id不能为空'));
        }
        $device_info = Db::table('up__sensor')
            ->where('app_sb_id', $app_sb_id)
            ->find();
        if (!$device_info) {
            $number     = rand(1000, 9999);
            $app_id     = $this->getNumber($number);
            $qrcode_url = $this->createQRcode($app_id);
            $data       = [
                'app_sb_id'  => $app_sb_id,
                'app_id'     => $app_id,
                'app_number' => $app_id,
                'app_ercode' => $qrcode_url
            ];
            $res        = Db::table('up__sensor')->insert($data);
            if ($res) {
                $device_info = $data;
            } else {
                return json(array('status' => 100, 'msg' => '绑定失败，请刷新重试！'));
            }
        }
        return json(array('status' => 200, 'msg' => $device_info));
    }

    /**
     * 刷新浮点设备
     * @param $app_sb_id
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function updtDevice()
    {
        $app_sb_id = input('app_sb_id');
        if (empty($app_sb_id)) {
            return json(array('status' => 100, 'msg' => '设备id不能为空'));
        }

        $number     = rand(1000, 9999);
        $app_id     = $this->getNumber($number);
        $qrcode_url = $this->createQRcode($app_id);
        $data       = [
            'app_sb_id'  => $app_sb_id,
            'app_id'     => $app_id,
            'app_number' => $app_id,
            'app_ercode' => $qrcode_url
        ];

        $device_info = Db::table('up__sensor')
            ->where('app_sb_id', $app_sb_id)
            ->find();
        if ($device_info) {
            Db::table('up__sensor')->where('app_sb_id', $app_sb_id)->delete();
        }
        $res = Db::table('up__sensor')->insert($data);
        if ($res) {
            $device_info = $data;
        } else {
            return json(array('status' => 100, 'msg' => '绑定失败，请刷新重试！'));
        }
        return json(array('status' => 200, 'msg' => $device_info));
    }

    /**
     * 更新、上传船只设备位置
     * @param $lat
     * @param $lon
     * @param $user_id
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function updBoatDevice()
    {
        $data['type'] = 1;
        //$data['sensor_id'] = input('id');
        $data['sensor_id'] = 'boat_' . input('id');
        $data['lat']       = input('lat');
        $data['lon']       = input('lon');
        if (!$data['sensor_id'] || !$data['lat'] || !$data['lon']) {
            return json(array('status' => 100, 'msg' => "参数不全！"));
        }
        $data['create_time'] = microtime(true);
        $this->redis->set($data['sensor_id'], json_encode($data));
        $res = Db::table('up__match_origin')->insert($data);
        return json(array('status' => 200, 'msg' => "success"));

    }

    /**
     * 更新、上传浮标设备位置
     * @param $lat    经度
     * @param $lon    纬度
     * @param $id
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function updBuoyDevice()
    {
//        header("Access-Control-Allow-Origin: *");
        $lat = input('lat');
        $lon = input('lon');
        //============= 设备定位，改动部分，用于设备定位   start  ==================//
//        $app_sb_id = input('app_sb_id');

        //****  高德
//        $data['lat']       = $lon;
//        $data['lon']       = $lat;
        //****  百度
        // 百度坐标系换算
//        $gps = new Gps();
//        $new_gps = $gps->delta($lon, $lat);
//        $new_lat = $lat + $new_gps['lon'];
//        $new_lon = $lon + $new_gps['lat'];
//        $app_id = Db::table('up__sensor')
//            ->where('app_sb_id', $app_sb_id)
//            ->value('app_id');
//        $data['sensor_id'] = $app_id;
//        $data['lat']       = $new_lon;
//        $data['lon']       = $new_lat;
        //============  设备定位，改动部分，用于设备定位    end  ==================//
        $data['type']      = 2;
        
        //===============  手机定位
        $data['lat']       = $lat;
        $data['lon']       = $lon;
        $data['sensor_id'] = input('id');
        
        
        if (!$data['sensor_id'] || !$data['lat'] || !$data['lat']) {
            return json(array('status' => 100, 'msg' => "参数不全！"));
        }
        $data['create_time'] = microtime(true);
        $this->redis->set($data['sensor_id'], json_encode($data));
        $res = Db::table('up__match_origin')->insert($data);
        return json(array('status' => 200, 'msg' => "success"));
    }

    /**
     * 获取所有设备
     * @param $match_id 比赛id
     * @param $match_detail_id 比赛轮次id 这两个参数必须有一个
     * @return {
     *          type:  设备类型  2启航线浮标 3终点线浮标 4普通浮标 5 船只
     * id:  设备id （当为船只时是用户id，当为浮标时是浮标四位数字id）
     * sensors: 传感器数组
     * sensor_id:  传感器id （当为船只时是boat_+用户id，当为浮标时是浮标四位数字id）
     * }
     */
    public function getAllDevice()
    {
        $res = $this->_getAllDevice(input());
        return json(array('status' => 200, 'msg' => $res));
    }


    /**
     * 获取某轮次的设备数据  需要复用 所以提取出来
     * @param $data
     * @return bool|\PDOStatement|string|\think\Collection|Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getAllDevice($data)
    {
        if (!$data['match_detail_id']) {
            if (!$data['match_id']) {
                return json(array('status' => 100, 'msg' => "参数不能同时为空！"));
            } else {
                //$m_d_id = Db::table('up__match_detail')->where(['match_id' => $data['match_id'], 'flag' => 0])->value('id');
                $m_d_id = Db::table('up__match_detail')
                    ->where(['match_id' => $data['match_id']])
                    ->order('id')
                    ->value('id');
                if (!$m_d_id) {
                    $m_d_id = Db::table('up__match_detail')->insertGetId(['match_id' => $data['match_id'], 'flag' => 0]);
                }
            }
        } else {
            $m_d_id = $data['match_detail_id'];
        }


        //将用户自动增加到比赛轮次相关设备组
        $match_detail_id = $data['match_detail_id'];
        $this->updateDeviceSensor($match_detail_id);

        $dmodel = new DeviceModel();
        return $dmodel->field('id,type,color')->relation(['sensors' => function ($query) use ($m_d_id) {
            $query->where('match_detail_id', $m_d_id)->field('sensor_id,name');
        }])->where('match_detail_id', $m_d_id)->order('type')->select();
    }

    //更新用户设备表
    public function updateDeviceSensor($m_d_id)
    {
        $m_d_info  = Db::table('up__match_detail')->where('id', $m_d_id)->find();
        $user_info = Db::table('up_match_apply_info')->where([
            'ma_match_id'    => $m_d_info['match_id'],
            'ma_group'       => $m_d_info['level_id'],
            'ma_sgin_status' => 2
        ])->column('ma_user_id');

        foreach ($user_info as $k => $v) {
            $res = Db::table('up__sensor_device')->where([
                'match_detail_id' => $m_d_id,
                'sensor_id'       => 'boat_' . $v,
            ])->find();

            if (!$res) {
                $device_id = Db::table('up__device')->insertGetId([
                    'name'            => '用户' . $v,
                    'type'            => 5,
                    'color'           => randrgb(),
                    'match_detail_id' => $m_d_id
                ]);
                $ress      = Db::table('up__sensor_device')->insertGetId([
                    'name'            => '用户' . $v,
                    'sensor_id'       => 'boat_' . $v,
                    'device_id'       => $device_id,
                    'match_detail_id' => $m_d_id
                ]);
            }
        }

        //初始化缓存
        $up__sensor_device = Db::table('up__sensor_device')
            ->where('sensor_id', 'like', '%boat_%')
            ->where('match_detail_id', $m_d_id)
            ->field('sensor_id,match_detail_id')->select();
        Cache::set('up__sensor_device', $up__sensor_device);

        $all_sensors_id = Db::table('up__sensor_device')
            ->where('match_detail_id', $m_d_id)->field('sensor_id,match_detail_id')->select();
        $sensors_id_arr = [];
        foreach ($all_sensors_id as $k => $v) {
            array_push($sensors_id_arr, $v['sensor_id']);
        }
        Cache::set('all_sensors_id', $all_sensors_id);
        Cache::set('sensors_id_arr', $sensors_id_arr);


        return true;
    }

    /**
     * 获取实时竞赛数据
     * @param $match_detail_id '比赛轮次id'
     */
    public function getLiveDatas()
    {
        $data['match_detail_id'] = input('match_detail_id');
        $data['match_id']        = input('match_id');
        $m_d_id                  = '';
        if (!$data['match_detail_id']) {
            if (!$data['match_id']) {
                return json(array('status' => 100, 'msg' => "参数不能同时为空！"));
            } else {
                $m_d_id = Db::table('up__match_detail')
                    ->where(['match_id' => $data['match_id']])
                    ->order('id')
                    ->value('id');
                if (!$m_d_id) {
                    $m_d_id = Db::table('up__match_detail')->insertGetId(['match_id' => $data['match_id'], 'flag' => 0]);
                }
            }
        } else {
            $m_d_id = $data['match_detail_id'];
        }
        Log::error('===================开始获取成绩' . microtime(true));
        $match_turns         = Db::table('up__match_detail')->where(['id' => $m_d_id])->find();
        $time                = time();
        $time_scope          = $time - 1;
        $boat_calculate_data = [];
        if ($match_turns['flag'] != 0) {
//            $boat_calculate_data = Db::table('up__match_datas')
//                ->where(['match_detail_id' => $m_d_id])
//                ->where('time', '>', $time_scope)
//                ->where('time', '<=', $time)
//                ->value('data');
            $boat_calculate_data = json_decode($this->redis->get('up__match_datas'));


            //$boat_calculate_data = json_decode($boat_calculate_data, true);
        } else {
            $up__sensor_device = Cache::get('up__sensor_device');
            if (!$up__sensor_device || $up__sensor_device[0]['match_detail_id'] != $m_d_id) {
                $up__sensor_device = Db::table('up__sensor_device')
                    ->where('sensor_id', 'like', '%boat_%')
                    ->where('match_detail_id', $m_d_id)
                    ->field('sensor_id,match_detail_id')->select();
                Cache::set('up__sensor_device', $up__sensor_device);
            }
            $boat_calculate_data = Cache::get('boat_calculate_data');
            //dump($boat_calculate_data);die;
            if (!$boat_calculate_data || (is_array($boat_calculate_data) && ($boat_calculate_data[0]['md_id'] != $m_d_id) || (count($boat_calculate_data) != count($up__sensor_device)))) {
                $boat_calculate_data = [];
                foreach ($up__sensor_device as $k => $v) {
                    $user_id   = str_replace('boat_', '', $v['sensor_id']);
                    $user_info = Db::table('up_match_apply_info')
                        ->alias('ai')
                        ->join("up_u_user u", "u.user_id = ai.ma_user_id ", 'LEFT')
                        ->join("up_club c", "c.club_id = u.user_club_id ", 'LEFT')
                        ->where(['ma_user_id' => $user_id])
                        ->field('u.user_id,u.user_username,ai.ma_fan_code,
                ai.ma_boat_code,c.club_name,c.club_image')
                        ->find();
                    $temp      = [
                        'md_id'               => $m_d_id,
                        //帆船参数计算结果
                        "device_id"           => $v['sensor_id'], //设备id
                        "ranking"             => $k + 1, //排名
                        //"next_points_id"    => 1, //下一个目标坐标，设备id
                        "next_points_lat"     => 1, //下一个目标坐标
                        "next_points_lon"     => 1, //下一个目标坐标
                        "speed"               => 0, //速度
                        "isoparmspeed"        => 0, //水平速度
                        "to_final_distance"   => 1000, //距终点距离
                        "to_first_distance"   => 0, //距第一名距离
                        "to_prior_distance"   => 1000, //距前一名距离
                        "to_start_distance"   => 0, //距起始线距离
                        "angle"               => 0, //角度（与正北夹角）
                        "rules_flag"          => 0,//是否犯规0未犯规1已犯规
                        "start_line_time"     => 0, //距起始线距离
                        "start_line_location" => 89,//穿越启航线角度
                        "start_line_speed"    => 0, //角度（与正北夹角）
                        "to_start_angle"      => 89,//穿越启航线角度
                        "user_id"             => $user_info['user_id'],//是否犯规0未犯规1已犯规
                        "user_username"       => $user_info['user_username'], //距起始线距离
                        "ma_fan_code"         => $user_info['ma_fan_code'],//穿越启航线角度
                        "club_image"          => $user_info['club_image'], //角度（与正北夹角）
                        "club_name"           => $user_info['club_name'],//穿越启航线角度
                    ];
                    Log::error('===================' . $k . '开始获取成绩' . microtime(true));
                    array_push($boat_calculate_data, $temp);
                }
                Cache::set('boat_calculate_data', $boat_calculate_data);
            }

        }
        //$location_data = Db::table('up__match_step')->where(['match_detail_id' => $m_d_id, 'time' => $time])->value('data');
        //$location_data = json_decode($location_data, true);
        $location_data = [];
        Log::error('===================开始获取位置' . microtime(true));
        //比赛之前没有快照则从原始表获取数据
        $all_sensors_id = Cache::get('all_sensors_id');
        $sensors_id_arr = Cache::get('sensors_id_arr');

        if (!$all_sensors_id || $all_sensors_id[0]['match_detail_id'] != $m_d_id) {
            $all_sensors_id = Db::table('up__sensor_device')
                ->where('match_detail_id', $m_d_id)->field('sensor_id,match_detail_id')->select();
            Cache::set('all_sensors_id', $all_sensors_id);
            $sensors_id_arr = [];
            foreach ($all_sensors_id as $k => $v) {
                array_push($sensors_id_arr, $v['sensor_id']);
            }
            Cache::set('sensors_id_arr', $sensors_id_arr);
        }
        foreach ($all_sensors_id as $k => $v) {
            $location_data[$v['sensor_id']] = $this->redis->get($v['sensor_id']);
        }


        Log::error('===================结束获取成绩' . microtime(true));

        if (input('version')==2){
            $data = [
                "match_detail_id"     => $m_d_id, //比赛轮次id
                "time"                => $time, // 时间戳
                "calculate_data"      => $boat_calculate_data, //船只参数计算结果
                "locations_data"      => $location_data, // 所有传感器位置
                "match_turns_data"    => $match_turns
            ];
        }else{
            $data = [
                "match_detail_id"     => $m_d_id, //比赛轮次id
                "time"                => $time, // 时间戳
                "boat_calculate_data" => $boat_calculate_data, //船只参数计算结果
                "location_data"       => $location_data, // 所有传感器位置
                "match_turns_data"    => $match_turns
            ];
        }

        return json(array('status' => 200, 'msg' => $data));

    }

    /**
     * 获取比赛所有组别
     * @param $match_id 比赛轮次id
     * @return success
     */
    public function getAllLevels()
    {
        $match_id = input('match_id');
        if (!$match_id) {
            return json(array('status' => 100, 'msg' => '比赛id不能为空'));
        }
        $all_level = Db::table("up_match_apply_group")
            ->alias('ag')
            ->join('up_match_group g', 'g.mg_id=ag.mag_group_id', 'LEFT')
            ->where('mag_match_id', $match_id)
            ->field('g.mg_name,g.mg_id,g.mg_image,ag.mag_match_id')
            ->select();
        return json(array('status' => 200, 'msg' => 'success', 'data' => $all_level));

    }


    /**
     * 获取比赛临时成绩
     * @param $match_id 比赛轮次id
     * @param $mg_id 比赛组别id
     * @return success
     */
    public function getTempScore()
    {
        try {
            $match_id = input('match_id');
            $mg_id    = input('mg_id');
            if (!$match_id || !$mg_id) {
                return json(array('status' => 100, 'msg' => '比赛id或组别id不能为空'));
            }
            $all_details = Db::table('up__match_detail')
                ->alias('md')
                ->where('md.match_id', $match_id)
                ->where('md.level_id', $mg_id)
                ->where('md.flag', 3)
                ->order('md.turn asc')
                ->field('md.id,md.match_id')
                ->select();
            //获取所有选手临时成绩
            if ($all_details != []) {
                $del_data = [];//被去掉成绩的数据
                $data     = $this->getSCore($mg_id, $match_id, $all_details, $del_data);
                if (count($all_details) >= 2) {
                    array_pop($all_details);
                    $del_data_bak = [];
                    $data_last    = $this->getSCore($mg_id, $match_id, $all_details, $del_data_bak);
                    foreach ($data as $k => $v) {
                        foreach ($data_last as $kk => $vv) {
                            if ($v['user_id'] == $vv['user_id']) {
                                $data[$k]['float'] = $v['placing'] - $vv['placing'];
                            }
                        }
                    }
                } else {
                    foreach ($data as $k => $v) {
                        $data[$k]['float'] = 0;
                    }
                }
                return json(array('status' => 200, 'msg' => 'success', 'data' => $data, 'to_delete_data' => $del_data));
            } else {
                return json(array('status' => 200, 'msg' => '比赛还没有结束', 'data' => [], 'to_delete_data' => []));
            }
        } catch (\Exception $e) {
            return json(array('status' => 100, 'msg' => $e->getMessage()));
        }
    }

    /**
     * 比赛成绩计算
     * @param $mg_id  组别id
     * @param $match_id 比赛id
     * @param $all_details 所有比赛轮次
     * @return success
     */
    public function getSCore($mg_id, $match_id, $all_details, &$del_data)
    {
        $temp_score_arr = [];
        //获取要轮次分段信息（即几轮比赛后去掉一个最低成绩）
        $escape_info = Db::table('up_match')->where('match_id', $match_id)->field('match_mark_max_num,match_mark_lunci')->find();
        $all_user    = Db::table('up_match_apply_info')
            ->where('ma_match_id', $match_id)
            ->where('ma_group', $mg_id)
            ->column('ma_user_id');
        //所有用户
        $all_user_temp_score = [];
        //获取所有用户成绩（有的需要去掉最差成绩）
        foreach ($all_details as $k => $v) {
            //获取某轮次比赛成绩
            $temp_score = Db::table('up__match_arrive_record ar ')
                ->where(['match_detail_id' => $v['id']])
                ->column('ar.temp_score,ar.sensor_id,ar.match_detail_id', 'ar.sensor_id');
            array_push($temp_score_arr, $temp_score);
            //如果有设置相关参数
            if ($escape_info['match_mark_lunci'] && $escape_info['match_mark_max_num']) {

                if ((($k + 1) % $escape_info['match_mark_lunci']) == 0) {

                    $count    = count($temp_score_arr);
                    $temp_arr = array_slice($temp_score_arr, $count - $escape_info['match_mark_lunci'], $escape_info['match_mark_lunci']);
                    foreach ($all_user as $ko => $vo) {
                        //每个用户比较成绩
                        $user_scor_temp_arr = $temp_arr;
                        for ($i = 0; $i < $escape_info['match_mark_lunci']; $i++) {
                            for ($j = $i + 1; $j < $escape_info['match_mark_lunci']; $j++) {
                                // 比较数组中两个相邻值的大小
                                if ($user_scor_temp_arr[$i]['boat_' . $vo]['temp_score'] > $user_scor_temp_arr[$j]['boat_' . $vo]['temp_score']) {
                                    $tem                                   = $user_scor_temp_arr[$i]['boat_' . $vo]; // 这里临时变量，存贮$i的值
                                    $user_scor_temp_arr[$i]['boat_' . $vo] = $user_scor_temp_arr[$j]['boat_' . $vo]; // 第一次更换位置
                                    $user_scor_temp_arr[$j]['boat_' . $vo] = $tem; // 完成位置互换
                                }
                            }
                        }
                        foreach ($user_scor_temp_arr as $kh => $vh) {
                            if ($kh >= ($escape_info['match_mark_lunci'] - $escape_info['match_mark_max_num'])) {
                                foreach ($temp_arr as $kt => $vt) {
                                    if ($vh['boat_' . $vo]['match_detail_id'] == $vt['boat_' . $vo]['match_detail_id']) {
                                        $temp_score_arr[$kt]['boat_' . $vo]['temp_score'] = 0;
                                        array_push($del_data, ['user_id' => $vo, 'match_detail_id' => $vh['boat_' . $vo]['match_detail_id']]);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        //计算累加成绩
        $user_all_grand_total = [];
        $user_grand_total     = [];
        foreach ($all_user as $ke => $ve) {
            $user_grand_total[$ve] = 0;
            foreach ($temp_score_arr as $kz => $vz) {
                $user_grand_total[$ve] += $vz['boat_' . $ve]['temp_score'];
            }
            array_push($user_all_grand_total, ['user_id' => $ve, 'score' => $user_grand_total[$ve]]);
        }

        $this->my_sort($user_all_grand_total, $temp_score_arr);


        $data = [];
        foreach ($user_all_grand_total as $ky => $ve) {
            $record            = Db::table('up_match_apply_info')
                ->alias('ai')
                ->join("up_u_user u", "u.user_id = ai.ma_user_id ", 'LEFT')
                ->join("up_match_group g", "g.mg_id = ai.ma_group ", 'LEFT')
                ->join("up_club c", "c.club_id = u.user_club_id ", 'LEFT')
                ->where(['ai.ma_match_id' => $match_id, 'ai.ma_group' => $mg_id, 'ma_user_id' => $ve['user_id']])
                ->field('u.user_id,u.user_username,u.user_gender,ai.ma_fan_code,
                ai.ma_boat_code,g.mg_name,g.mg_image,c.club_name,c.club_image')
                ->find();
            $record['placing'] = $ky + 1;
            $record['score']   = $ve['score'];
            array_push($data, $record);
        }
        return $data;
    }


    /**
     * 比赛成绩排序
     * @param $arr  用户总成绩数组
     * @param $temp_score_arr 用户每轮比赛成绩数组
     * @return success
     */

    public function my_sort(&$arr, $temp_score_arr)
    {
        $end_limit = count($arr) + 2;
        $count     = count($arr);
        for ($i = 0; $i < $count; $i++) {
            for ($j = $i + 1; $j < $count; $j++) {
                //不同分数
                if ($arr[$i]['score'] > $arr[$j]['score']) {
                    $tem     = $arr[$i]; // 这里临时变量，存贮$i的值
                    $arr[$i] = $arr[$j]; // 第一次更换位置
                    $arr[$j] = $tem; // 完成位置互换
                } elseif ($arr[$i]['score'] == $arr[$j]['score']) {
                    //相同分数，比小分
                    //先计算累加成绩
                    $flag = 0;//用于判断是否需要判断最后一轮次比赛成绩
                    for ($s = 1; $s <= $end_limit; $s++) {
                        $temp_first  = 0;
                        $temp_second = 0;
                        foreach ($temp_score_arr as $key => $value) {
                            if ($value['boat_' . $arr[$i]['user_id']]['temp_score'] == $s) {
                                $temp_first++;
                            }
                            if ($value['boat_' . $arr[$j]['user_id']]['temp_score'] == $s) {
                                $temp_second++;
                            }
                        }
                        if ($temp_first < $temp_second) {
                            $tem     = $arr[$i]; // 这里临时变量，存贮$i的值
                            $arr[$i] = $arr[$j]; // 第一次更换位置
                            $arr[$j] = $tem; // 完成位置互换
                            $flag    = 1;
                            break;
                        } elseif ($temp_first == $temp_second) {
                            continue;
                        } else {
                            $flag = 1;
                        }
                        //判断是否需要判断最后一轮次比赛成绩
                        if ($flag == 0) {
                            $temp_first_boat  = $arr[$count - 1]['boat_' . $arr[$i]['user_id']]['temp_score'];
                            $temp_second_boat = $arr[$count - 1]['boat_' . $arr[$j]['user_id']]['temp_score'];
                            if ($temp_first_boat > $temp_second_boat) {
                                $tem     = $arr[$i]; // 这里临时变量，存贮$i的值
                                $arr[$i] = $arr[$j]; // 第一次更换位置
                                $arr[$j] = $tem; // 完成位置互换
                            }
                        }
                    }
                } else {
                    continue;
                }
            }
        }
    }

    /**
     * 复制前一轮次未完成的比赛
     * @param $match_detail_id 轮次id  必须
     */
    public function reCreateMatch()
    {
        $m_d_id = input('match_detail_id');
        if (!$m_d_id) {
            return json(array('status' => 100, 'msg' => "轮次id不能为空！"));
        }
        try {
            $data = $info = Db::table('up__match_detail')->where(['id' => $m_d_id, 'flag' => 2])->find();
            if (!$info) {
                return json(array('status' => 100, 'msg' => "该伦次已经正常结束或不存在！"));
            }
            $data['flag'] = 0;
            unset($data['end_time']);
            unset($data['start_time']);
            unset($data['id']);
            $data['flag_start_id'] = $data['flag_start_id_bak'];
            //更新之前废弃数据
            Db::table('up__match_detail')->where([
                'flag'=>'0',
                'match_id'=>$data['match_id'],
                'level_id'=>$data['level_id']
            ])->update(['flag' => '2']);
            //新建对应轮次
            $new_match_detail_id = Db::table('up__match_detail')->insertGetId($data);
            //查询对应赛段信息并插入
            $line_info = Db::table('up__match_line')->where(['match_detail_id' => $m_d_id])->select();
            foreach ($line_info as $k => $v) {
                $v['match_detail_id'] = $new_match_detail_id;
                unset($v['id']);
                Db::table('up__match_line')->insert($v);
            }
            //查询对应设备信息并插入
            $device_info = Db::table('up__device')->where(['match_detail_id' => $m_d_id])->select();
            foreach ($device_info as $k => $v) {
                $v['match_detail_id'] = $new_match_detail_id;
                unset($v['id']);
                $new_device_id      = Db::table('up__device')->insertGetId($v);
                $device_sensor_info = Db::table('up__sensor_device')
                    ->where([
                        'match_detail_id' => $m_d_id,
                        'device_id'       => $device_info[$k]['id']
                    ])->select();
                foreach ($device_sensor_info as $key => $value) {
                    $value['match_detail_id'] = $new_match_detail_id;
                    $value['device_id']       = $new_device_id;
                    unset($value['id']);
                    Db::table('up__sensor_device')->insert($value);
                }
            }
            return json(array('status' => 200, 'msg' => "success", 'data' =>[
                'match_detail_id'=>$new_match_detail_id,
                'match_detail'=>$this->_match_detail_info($new_match_detail_id)
            ]));
        } catch (\Exception $e) {
            return json(array('status' => 100, 'msg' => $e->getMessage()));
        }


    }

    /**
     * 开始某个轮次的比赛
     * @param $user_id 裁判长id  必须
     * @param $match_detail_id 比赛轮次id
     * @return success
     */
    public function beginMatchTurns()
    {
        $data['match_detail_id'] = input('match_detail_id');
        $data['operation_uid']   = input('user_id');

//        if (!$data['match_detail_id'] || !$data['operation_uid']) {
//            return json(array('status' => 100, 'msg' => "参数不能为空"));
//        }
        try {
            $match_turns_info = Db::table("up__match_detail")->alias('d')->join("up_match m", "m.match_id=d.match_id")->field('m.match_zong_user_id,d.*')->where('d.id', $data['match_detail_id'])->find();
            if ($match_turns_info['match_zong_user_id'] != $data['operation_uid']) {
                return json(array('status' => 100, 'msg' => "此用户没有权限开始比赛！"));
            }
            //去掉不是必填的字段
            unset($match_turns_info['match_zong_user_id']);
            unset($match_turns_info['flag_start_id']);
            unset($match_turns_info['flag_start_id_bak']);
            unset($match_turns_info['flag_signal_id']);
            unset($match_turns_info['start_data']);
            unset($match_turns_info['start_time']);
            unset($match_turns_info['end_time']);
            unset($match_turns_info['flag']);
            foreach ($match_turns_info as $k => $v) {
                if ($v == '' || $v == null) {
                    if ($k == 'turn') {
                        $k = '比赛轮次';
                    } elseif ($k == 'level_id') {
                        $k = '比赛级别';
                    } elseif ($k == 'e_fence') {
                        $k = '电子围栏';
                    } elseif ($k == 'flag_start_id') {
                        $k = '起航旗';
                    } elseif ($k == 'msi_id') {
                        $k = '航线图';
                    } else {
                        $k = $k;
                    }
                    return json(array('status' => 100, 'msg' => "请完善比赛参数{$k}再开始比赛"));
                }
            }
            //不能重复轮次
            $res_info = Db::table('up__match_detail')->where([
                'level_id' => $match_turns_info['level_id'],
                'turn'     => $match_turns_info['turn'],
                'match_id' => $match_turns_info['match_id'],
                'flag'     => 3
            ])->find();
            if ($res_info) {
                return json(array('status' => 100, 'msg' => "该比赛第".$match_turns_info['turn']."轮已经完成，请选择其他轮次再开始比赛！",'data'=>$res_info));
            }

            $sensor_device_info = Db::table("up__sensor_device")->where('match_detail_id', $data['match_detail_id'])->column('sensor_id');
            foreach ($sensor_device_info as $k => $v) {
                if ($v == '' || $v == null) {
                    return json(array('status' => 100, 'msg' => "请完善比赛路径参数再开始比赛"));
                }
            }
            //设备不能重复绑定
            $sensor_device_all_info = Db::table("up__sensor_device")->where('match_detail_id', $data['match_detail_id'])->select();
            foreach ($sensor_device_all_info as $k => $v) {
                foreach ($sensor_device_all_info as $m => $n) {
                    if (($v['name'] != $n['name']) && $v['sensor_id'] == $n['sensor_id']) {
                        if (!($v['name'] == 'SP' || $v['name'] == 'SS' || $v['name'] == 'FP' || $v['name'] == 'FS')
                            || !($n['name'] == 'SP' || $n['name'] == 'SS' || $n['name'] == 'FP' || $n['name'] == 'FS')) {
                            return json(array('status' => 100, 'msg' => "除起始设备，一台设备id只能绑定一个坐标点" . $n['name'] . ' ' . $v['name'] . "重复绑定"));
                        }
                    }
                }
            }
            //清空设备赛道绑定表，再添加
            $del_up__match_line = Db::table('up__match_line')->where('match_detail_id', $data['match_detail_id'])->delete();
            $msi_raobiao        = Db::table('up_match_sail_image')->where('msi_id', $match_turns_info['msi_id'])->value('msi_raobiao');
            $points_arr         = explode('-', $msi_raobiao);

            //将所有绑定浮标，依照绕标顺序插入match_line表
            $sensor_arr = [];
            $boat_arr   = [];
            $data_arr   = [];
            foreach ($points_arr as $k => $v) {
                $temp          = [];
                $pointsAndRule = explode('@', $v);
                $points        = $pointsAndRule[0];
                $rule          = $pointsAndRule[1];
                //取得传感器列表
                $sensor_name_list = [];
                if (strstr('&', $points)) {
                    $sensor_name_list = explode('&', $points);
                } else {
                    $sensor_name_list = explode('/', $points);
                }
                //获得sensor_id
                $temp_sensor = [];
                foreach ($sensor_name_list as $key => $value) {
                    $sensor_id                     = Db::table('up__sensor_device')->where([
                        'match_detail_id' => $data['match_detail_id'],
                        'name'            => $value
                    ])->value('sensor_id');
                    $i                             = $key + 1;
                    $temp['sensor' . $i . '_name'] = $value;
                    $temp['sensor' . $i . '_id']   = $sensor_id;
                }
                $temp['match_detail_id'] = $data['match_detail_id'];
                $temp['points_name']     = $points;
                $temp['rule_type']       = $rule;
                //赛段绑定
                Db::table("up__match_line")->insert($temp);
                array_push($data_arr, $temp);
            }
            //dump($data_arr);die;
            //Db::table("up__match_line")->insertAll($data_arr);
            //将所有船加入数组
            $boat_arr = Db::table('up__sensor_device')
                ->where('match_detail_id', $data['match_detail_id'])
                ->where('sensor_id', 'like', '%boat_%')
                ->column('sensor_id');
            //初始化记录表
            $start_time = $this->record_table($data['match_detail_id'], $boat_arr);
            Log::error("+++++++" . $data['match_detail_id'] . "比赛初始化+++++++");
            //开启定时数据计算
            (new QueueService())->startMatch($data['match_detail_id']);
            Log::error("+++++++" . $data['match_detail_id'] . "比赛开始+++++++");
            return json(array('status' => 200, 'msg' => "比赛开始",'start_time'=>$start_time));
        } catch (\think\Exception $e) {
            return json(array('status' => 100, 'msg' => "比赛开始失败" . $e->getMessage()));
        }


    }

    /**
     * 创建record记录
     * @param $m_d_id 比赛轮次id  必须
     * @param $boat_arr 所有船只id
     */
    public function record_table($m_d_id = 16, $boat_arr = [])
    {
        //temp_limit_time
        $match_detail = Db::table('up__match_detail')->where('id', $m_d_id)->find();
        $match_info   = Db::table('up_match')->where('match_id', $match_detail['match_id'])->find();
        if (!$match_info['match_zhong_limit']) {
            throw new Exception('请现在后台设置终点时限', 4);
        }
        if (!$match_info['match_feng_limit']) {
            throw new Exception('请现在后台设置封闭时限', 4);
        }
        if (!$match_info['match_first_feng_limit']) {
            throw new Exception('请现在后台设置一标封闭时限', 4);
        }
        //开始比赛
        $start_time = microtime(true);
        Db::table("up__match_detail")->where('id', $m_d_id)->update([
            'start_time' => $start_time,
            'flag'       => 1
        ]);
        //各种时间节点初始化
        //$start_time            = $match_detail['start_time'];
        $this->temp_start_time        = $start_time;//比赛开始倒计时时间
        $this->temp_one_time          = $start_time + $this->temp_countdown;//比赛开始倒计时到1分钟时间
        $this->temp_zero_time         = $start_time + $this->temp_all_countdown;//比赛倒计时为0时间
        $this->temp_four_time         = $start_time + $this->temp_all_countdown + $this->temp_countdown;//比赛正计时为4分钟时间
        $this->match_zhong_limit      = $this->temp_zero_time + $match_info['match_zhong_limit'] * 60;//终点时限
        $this->match_feng_limit       = $match_info['match_feng_limit'] * 60;//封闭时限
        $this->match_first_feng_limit = $this->temp_zero_time + $match_info['match_first_feng_limit'] * 60;//1标封闭时限
        $this->match_start_limit      = $this->temp_zero_time + 9 * 60;//过启航线最晚时间

        $this->match_flag_id   = $match_detail['flag_start_id'];
        $this->temp_boat_count = count($boat_arr);
        //获取所有之前取消的比赛，如果有起航旗为黑旗的
        $match_details = Db::table('up__match_detail')->where([
            'match_id'          => $match_detail['match_id'],
            'turn'              => $match_detail['turn'],
            'level_id'          => $match_detail['level_id'],
            'flag_start_id_bak' => $this->b_flag_id,
            'flag'              => 2
        ])->column('id');
        //循环查找是否有选手在起航旗为黑旗，犯规过,并将其放到一个数组内
        $break_rules_user_list = [];
        if (is_array($match_details)) {
            $break_rules_user_list = Db::table('up__match_arrive_record')
                ->where('match_detail_id', 'in', $match_details)
                ->where('rules_flag', '<>', 0)
                ->column('sensor_id');
            if (is_array($break_rules_user_list) && $break_rules_user_list != []) {
                $break_rules_user_list = array_unique($break_rules_user_list);
            }
        }


        Db::table('up__match_arrive_record')->where('match_detail_id', $m_d_id)->delete();
        $this->temp_record       = [];
        $this->temp_record_last  = [];
        $this->temp_lines_idkey  = [];
        $this->temp_all_distance = 0;
        $this->temp_lines        = Db::table('up__match_line')->where('match_detail_id', $m_d_id)->order('id')->select();
        foreach ($this->temp_lines as $key => $value) {
            $res                            = json_decode($this->redis->get($this->temp_lines[$key]['sensor1_id']), true);
            $this->temp_lines[$key]['lat1'] = $res['lat'];
            $this->temp_lines[$key]['lon1'] = $res['lon'];
            if ($this->temp_lines[$key]['sensor2_id']) {
//                $res2                           = Db::table('up__match_origin')
//                    ->where('sensor_id', $this->temp_lines[$key]['sensor2_id'])
//                    ->order('create_time desc')->find();
                $res2                           = json_decode($this->redis->get($this->temp_lines[$key]['sensor2_id']), true);
                $this->temp_lines[$key]['lat2'] = $res2['lat'];
                $this->temp_lines[$key]['lon2'] = $res2['lon'];
            }
            $this->temp_lines_idkey[$value['id']] = $this->temp_lines[$key];
        }

        foreach ($this->temp_lines as $key => $value) {
            $distance = 0;
            //下一个目标点经纬度
            $next_points = [];
            //初始化路径长度
            if ($this->temp_lines[$key]['rule_type'] == 1) {
                $next_start_points = ['lat' => $this->temp_lines[$key]['lat1'], 'lon' => $this->temp_lines[$key]['lon1']];
                $next_end_points   = ['lat' => $this->temp_lines[$key]['lat2'], 'lon' => $this->temp_lines[$key]['lon2']];
                $next_points       = $this->getMiddlePoint($next_start_points, $next_end_points);
                $distance          = 0;
            } elseif (($this->temp_lines[$key]['rule_type'] == 6 || $this->temp_lines[$key]['rule_type'] == 7
                    || $this->temp_lines[$key]['rule_type'] == 8 || $this->temp_lines[$key]['rule_type'] == 9
                ) && ($this->temp_lines[$key - 1]['rule_type'] == 6 || $this->temp_lines[$key - 1]['rule_type'] == 7
                    || $this->temp_lines[$key - 1]['rule_type'] == 8 || $this->temp_lines[$key - 1]['rule_type'] == 9
                )) {
                //目标点到目标点距离
                $start       = ['lat' => $this->temp_lines[$key - 1]['lat1'], 'lon' => $this->temp_lines[$key - 1]['lon1']];
                $end         = ['lat' => $this->temp_lines[$key]['lat1'], 'lon' => $this->temp_lines[$key]['lon1']];
                $next_points = $end;
                $distance    = $this->getMiddleDistance($start, $end);
            } elseif (($this->temp_lines[$key]['rule_type'] == 2 || $this->temp_lines[$key]['rule_type'] == 3
                    || $this->temp_lines[$key]['rule_type'] == 4 || $this->temp_lines[$key]['rule_type'] == 5
                ) && ($this->temp_lines[$key - 1]['rule_type'] == 1 || $this->temp_lines[$key - 1]['rule_type'] == 3
                    || $this->temp_lines[$key - 1]['rule_type'] == 4 || $this->temp_lines[$key - 1]['rule_type'] == 5
                )) {
                //求双坐标直线，求中点到中点距离
                $last_start  = ['lat' => $this->temp_lines[$key - 1]['lat1'], 'lon' => $this->temp_lines[$key - 1]['lon1']];
                $last_end    = ['lat' => $this->temp_lines[$key - 1]['lat2'], 'lon' => $this->temp_lines[$key - 1]['lon2']];
                $now_start   = ['lat' => $this->temp_lines[$key]['lat1'], 'lon' => $this->temp_lines[$key]['lon1']];
                $now_end     = ['lat' => $this->temp_lines[$key]['lat2'], 'lon' => $this->temp_lines[$key]['lon2']];
                $next_points = $this->getMiddlePoint($now_start, $now_end);
                $distance    = $this->getMiddleDistance($last_start, $last_end, $now_start, $now_end);
            } elseif (($this->temp_lines[$key]['rule_type'] == 6 || $this->temp_lines[$key]['rule_type'] == 7
                    || $this->temp_lines[$key]['rule_type'] == 8 || $this->temp_lines[$key]['rule_type'] == 9
                ) && ($this->temp_lines[$key - 1]['rule_type'] == 1 || $this->temp_lines[$key - 1]['rule_type'] == 3
                    || $this->temp_lines[$key - 1]['rule_type'] == 4 || $this->temp_lines[$key - 1]['rule_type'] == 5
                )) {
                //求双坐标直线，求中点到点距离
                $last_start  = ['lat' => $this->temp_lines[$key - 1]['lat1'], 'lon' => $this->temp_lines[$key - 1]['lon1']];
                $last_end    = ['lat' => $this->temp_lines[$key - 1]['lat2'], 'lon' => $this->temp_lines[$key - 1]['lon2']];
                $now         = ['lat' => $this->temp_lines[$key]['lat1'], 'lon' => $this->temp_lines[$key]['lon1']];
                $next_points = $now;
                $distance    = $this->getMiddleDistance($last_start, $last_end, $now);
            } else {
                //求双坐标直线，求中点到点距离
                $now_start   = ['lat' => $this->temp_lines[$key]['lat1'], 'lon' => $this->temp_lines[$key]['lon1']];
                $now_end     = ['lat' => $this->temp_lines[$key]['lat2'], 'lon' => $this->temp_lines[$key]['lon2']];
                $last        = ['lat' => $this->temp_lines[$key - 1]['lat1'], 'lon' => $this->temp_lines[$key - 1]['lon1']];
                $next_points = $this->getMiddlePoint($now_start, $now_end);
                $distance    = $this->getMiddleDistance($now_start, $now_end, $last);
            }
            $this->temp_lines[$key]['distance']        = $distance;
            $this->temp_lines[$key]['next_points_lat'] = $next_points['lat'];
            $this->temp_lines[$key]['next_points_lon'] = $next_points['lon'];
            //$this->temp_all_distance              += $distance;
            $this->temp_lines_idkey[$value['id']] = $this->temp_lines[$key];

        }

        $first_line = $this->temp_lines[0];
        //$start_points = ['lat' => $first_line['start_lat'], 'lon' => $first_line['start_lon']];
        //$end_points   = ['lat' => $first_line['end_lat'], 'lon' => $first_line['end_lon']];
        //如果没有，初始化船只赛段记录
        $rank = 1;
        foreach ($boat_arr as $k => $v) {
            $user_id   = str_replace('boat_', '', $v);
            $user_info = Db::table('up_match_apply_info')
                ->alias('ai')
                ->join('up_club c', 'c.club_id=ai.ma_club_id', "LEFT")
                ->join('up_u_user u', 'u.user_id=ai.ma_user_id', "LEFT")
                ->where('ai.ma_user_id', $user_id)
                ->field('c.club_image,c.club_name,c.club_id,ai.ma_fan_code,u.user_username')
                ->find();
            $data      = [
                'match_detail_id'     => $m_d_id,
                'sensor_id'           => $v,
                'user_id'             => $user_id,
                'user_username'       => $user_info['user_username'],
                'club_name'           => $user_info['club_name'],
                'club_image'          => $user_info['club_image'],
                'ma_fan_code'         => $user_info['ma_fan_code'],
                'distance'            => 0,
                'line_id'             => $first_line['id'],
                //'next_points_id'      => $first_line['end_sensor_id'],
                'next_points_lat'     => $first_line['next_points_lat'],
                'next_points_lon'     => $first_line['next_points_lon'],
                'rule_type'           => $first_line['rule_type'],
                'lat'                 => '',
                'lon'                 => '',
                'speed'               => 0,
                'time'                => '',
                //'to_final_distance'   => $this->temp_all_distance,
                'to_prior_distance'   => 0,
                'to_start_distance'   => 0,
                'to_first_distance'   => 0,
                'to_start_angle'      => 3,//到达起始线的角度',
                'angle'               => 0,
                'start_line_time'     => 0,
                'start_line_location' => 0,
                'start_line_speed'    => 0,
                'isoparmspeed'        => 0,
                'rules_flag'          => 0,
                'next_quadrant'       => '',
                'complete_quadrants'  => '',
                'ranking'             => $rank,
                'temp_score'          => $rank,
                'type'                => 1,
                'black_rules_flag'    => 0
            ];
            //黑旗选手
            if (in_array($v, $break_rules_user_list)) {
                $data['ranking']          = $this->temp_boat_count + 1;
                $data['rules_flag']       = 5;
                $data['temp_score']       = $this->temp_boat_count + 1;
                $data['black_rules_flag'] = 5;
            } else {
                $rank++;
            }

            $record_id             = Db::table('up__match_arrive_record')->insertGetId($data);
            $data['id']            = $record_id;
            $this->temp_record[$v] = $data;
        }
        $this->temp_record_last = $this->temp_record;

        $sensor_id_arr = Db::table('up__sensor_device')->where('match_detail_id', $m_d_id)->column('sensor_id');
        $this->redis->set('sensor_id_arr', json_encode($sensor_id_arr));
        return $start_time;
    }

    /**
     * 创建、修改某个轮次的比赛
     * @param $match_id 比赛id  必须
     * @param $match_detail_id 比赛轮次id
     * @param $operation_uid 操作人id
     * @param $turn  轮次
     * @param $level_id 级别id
     * @param $e_fence  电子围栏(单位米)
     * @param $flag_start_id   起航旗id
     * @param $flag_signal_id 信号旗id
     * @param $msi_id  航线图id
     * @param $points_key 设备绑定参数名字，即浮标名称，例 'SP'
     * @param $sensor_id 传感器id，例 3347
     */
    public function addMatchTurns()
    {
        try {

            $data                    = input();
            $data['match_id']        = input('match_id');
            $data['match_detail_id'] = input('match_detail_id');
            $data['msi_id']          = input('msi_id');
            $data['turn']            = input('turn');
            $data['level_id']        = input('level_id');
            $data['e_fence']         = input('e_fence');
            $data['flag_start_id']   = input('flag_start_id');
            $data['flag_signal_id']  = input('flag_signal_id');
            $data['points_key']      = input('points_key');
            $data['sensor_id']       = input('sensor_id');
            $match_detail_id         = '';
            if ($data['match_detail_id'] == "") {
                if ($data['match_id'] == "") {
                    return json(array('status' => 100, 'msg' => 'match_id和match_detail_id不能同时为空！'));
                } else {
                    $match_detail_id = Db::table('up__match_detail')
                        ->where(["match_id" => $data['match_id']])
                        ->where("flag", 'in', [0, 1])
                        ->value('id');
                    if (!$match_detail_id) {
                        $match_detail_id = Db::table('up__match_detail')->insertGetId(["match_id" => $data['match_id'], "flag" => 0]);
                    }
                }
            } else {
                $match_detail_id = $data['match_detail_id'];
            }


            if ($match_detail_id) {//执行更新
                $upd_data = [];//待更新数据数组
                //如果有线路图则更新线路图
                if ($data['msi_id']) {
                    $upd_data['msi_id'] = $data['msi_id'];
                    $map                = Db::table('up_match_sail_image')->where('msi_id', $data['msi_id'])->find();
                    $sensor_arr         = explode('-', $map['msi_biao_name']);
                    $match_device       = Db::table('up__device')->where('match_detail_id', $match_detail_id)->find();
                    //如果有相关设备信息，则清除后再添加相关设备
                    if ($match_device) {
                        Db::table('up__device')->where('match_detail_id', '=', $match_detail_id)
                            ->delete();//先删除相关设备配置
                        Db::table('up__sensor_device')->where(['match_detail_id' => $match_detail_id])->delete();//先删除相关设备配置
                    }
                    //将坐标点与设备点绑定
                    foreach ($sensor_arr as $k => $v) {
                        $v = (string)$v;
                        if ($v == "SS/SP" || $v == "SP/SS") {
                            $id = Db::table('up__device')->insertGetId(['type' => 2, 'match_detail_id' => $match_detail_id]);
                            Db::table('up__sensor_device')->insertAll([
                                ['name' => "SS", 'device_id' => $id, 'match_detail_id' => $match_detail_id],
                                ['name' => "SP", 'device_id' => $id, 'match_detail_id' => $match_detail_id]
                            ]);
                        } elseif ($v === "4p/4s" || $v === "4s/4p" || $v === "3p/3s" || $v === "3s/3p" || $v === "1&1a" || $v === "1a&1" || $v === "1/1a" || $v === "1a/1") {
                            $sensors_list = explode('/', $v);
                            if (count($sensors_list) == 1) {
                                $sensors_list = explode('&', $v);
                            }
                            $id = Db::table('up__device')->insertGetId(['type' => 4, 'match_detail_id' => $match_detail_id]);
                            Db::table('up__sensor_device')->insertAll([
                                ['name' => $sensors_list[0], 'device_id' => $id, 'match_detail_id' => $match_detail_id],
                                ['name' => $sensors_list[1], 'device_id' => $id, 'match_detail_id' => $match_detail_id]
                            ]);
                        } elseif ($v === "1" || $v === "2" || $v === "3" || $v === "4" || $v === "5" || $v === "S1" || $v === "S2" || $v === "S3") {
                            $id = Db::table('up__device')->insertGetId(['type' => 4, 'match_detail_id' => $match_detail_id]);
                            Db::table('up__sensor_device')->insert(['name' => $v, 'device_id' => $id, 'match_detail_id' => $match_detail_id]);
                        } elseif ($v === "FS/FP" || $v === "FP/FS") {
                            $id = Db::table('up__device')->insertGetId(['type' => 3, 'match_detail_id' => $match_detail_id]);
                            Db::table('up__sensor_device')->insertAll([
                                ['name' => "FS", 'device_id' => $id, 'match_detail_id' => $match_detail_id],
                                ['name' => "FP", 'device_id' => $id, 'match_detail_id' => $match_detail_id]
                            ]);
                        } else {

                        }
                    }
                }

                //更新比赛相关信息
                if ($data['turn']) {
                    $upd_data['turn'] = $data['turn'];
                }
                if ($data['level_id']) {
                    $upd_data['level_id'] = $data['level_id'];
                    Db::table('up__device')->where([
                        'match_detail_id' => $match_detail_id,
                        'type'            => 5
                    ])->delete();
                    Db::table('up__sensor_device')
                        ->where(['match_detail_id' => $match_detail_id])
                        ->where('sensor_id', 'like', '%boat_%')
                        ->delete();
                }
                if ($data['e_fence']) {
                    $upd_data['e_fence'] = $data['e_fence'];
                }
                if (key_exists('flag_start_id', $data)) {
                    if ($data['flag_start_id']) {
                        $upd_data['flag_start_id_bak'] = $data['flag_start_id'];
                    }
                    $upd_data['flag_start_id'] = $data['flag_start_id'];
                }
                if (key_exists('flag_signal_id', $data)) {
                    $upd_data['flag_signal_id'] = $data['flag_signal_id'];
                }

                $res = Db::table('up__match_detail')->where(["id" => $match_detail_id])->update($upd_data);

                //绑定浮标
                if ($data['sensor_id']) {
                    $res = Db::table('up__sensor')->where(['app_number' => $data['sensor_id']])->find();
                    if (!$res) {
                        return json(array('status' => 100, 'msg' => '设备号不存在'));
                    }
                    $sensor = Db::table('up__sensor_device')->where([
                        'sensor_id'       => $data['sensor_id'],
                        'match_detail_id' => $match_detail_id])->find();
                    if ($sensor) {
                        if (($sensor['name'] == "SS" || $sensor['name'] == "SP" || $sensor['name'] == "FS" || $sensor['name'] == "FP") &&
                            ($data['points_key'] == "SS" || $data['points_key'] == "SP" || $data['points_key'] == "FS" || $data['points_key'] == "FP")) {
                            Db::table('up__sensor_device')->where([
                                'name' => $data['points_key'], 'match_detail_id' => $match_detail_id
                            ])->update(['sensor_id' => $data['sensor_id']]);
                        } else {
                            return json(array('status' => 100, 'msg' => '设备名不能绑定多次'));
                        }
                    } else {
                        Db::table('up__sensor_device')->where([
                            'name' => $data['points_key'], 'match_detail_id' => $match_detail_id
                        ])->update(['sensor_id' => $data['sensor_id']]);
                    }
                } else {
                    if ($data['points_key']) {
                        Db::table('up__sensor_device')->where([
                            'name' => $data['points_key'], 'match_detail_id' => $match_detail_id
                        ])->update(['sensor_id' => '']);
                    }/*else{
                        return json(array('status' => 100, 'msg' => '设备名不能为空'));
                    }*/
                }

            } else {
                //执行新增
                Db::table('up__match_detail')->insert(['match_id' => $data['match_id']]);
                $match_detail_id = Db::getLastInsID();//返回该轮次比赛id
            }
            $m_d_info = Db::table('up__match_detail')->where('id', $match_detail_id)->find();
            $this->redis->set('m_d_info_' . $match_detail_id, $m_d_info);
            //$this->checkDeviceBind($data['msi_id'], $data['points']);
            return json(array('status' => 200, 'msg' => [
                'match_detail'=>$this->_match_detail_info($match_detail_id),
                "match_detail_id" => $match_detail_id, 'getAllDevice' => $this->_getAllDevice(['match_detail_id' => $match_detail_id])]));
        } catch (\Exception $e) {
            return json(array('status' => 100, 'msg' => $e->getMessage(), 'data' => $e->getLine()));
        }
    }


    /**
     * 运动员端----获取比赛初始化数据
     * 获取当前轮次信息(旧版,在map_frm改造成Vue版本后应当废弃)
     * @param $match_id 比赛id
     */
    public function getTurnsnow()
    {
        $data['match_id'] = input('match_id');
        if (!$data['match_id']) {
            return json(array('status' => 100, 'msg' => "参数不能为空"));
        }
        $match_details = Db::table('up__match_detail')->where(['match_id' => $data['match_id']])->where('flag', 'in', [0, 1])->find();

        if ($match_details) {
            $data['level_id']       = Db::table('up_match_group')->where('mg_id', $match_details['level_id'])->find();
            $data['flag_start_id']  = Db::table('up_setsail_flag')->where('sf_id', $match_details['flag_start_id'])->find();
            $data['flag_signal_id'] = Db::table('up_flag_signal')->where('fs_id', $match_details['flag_signal_id'])->find();
            $data['msi_id']         = Db::table('up_match_sail_image')->where('msi_id', $match_details['msi_id'])->find();

            if ($data['msi_id']) {
                $temp = [];
                /*$data['msi_id']['msi_biao_name'] = explode('-', $data['msi_id']['msi_biao_name']);
                foreach ($data['msi_id']['msi_biao_name'] as $key => $value) {
                    if (strlen($value) > 2) {
                        $value = explode('/', $value);
                        if (count($value) < 2) {
                            $value = explode('&', $value);
                        }
                        $temp = array_merge($temp, $value);
                    } else {
                        array_push($temp, $value);
                    }

                }
                $data['msi_id']['msi_biao_name'] = implode('-', $temp);*/
                $bind      = Db::table('up__sensor_device')->where('match_detail_id', $match_details['id'])->select();
                $bind_data = [];
                foreach ($bind as $item) {
                    $bind_data[$item['name']] = $item['sensor_id'];
                }

                $data['bind'] = $bind_data;
            }


            $match_details['data']       = $data;
            $match_details['ready_time'] = Db::table('up__match_config')->where('param_name', 'ready_time')->value('param_value');

        }


        return json(array('status' => 200, 'msg' => $match_details));
    }


    /**
     * 新版的获取轮次信息
     * @return Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getTurnNow()
    {
        $data['match_id'] = input('match_id');
        if (!$data['match_id']) {
            return json(array('status' => 100, 'msg' => "参数不能为空"));
        }
        $match_detail_id = Db::table('up__match_detail')->where(['match_id' => $data['match_id']])->where('flag', 'in', [0, 1])->value('id');
        if ($match_detail_id) {
            $match_details['data']       = $this->_match_detail_info($match_detail_id);
            $match_details['ready_time'] = Db::table('up__match_config')->where('param_name', 'ready_time')->value('param_value');
            return json(array('status' => 200, 'msg' => $match_details));
        } else {
            return json(array('status' => 404, 'msg' => '暂无未开始的比赛'));
        }
    }


    /**
     * 获取标准统一的比赛信息
     * @param $match_detail_id
     * @return array|bool|\PDOStatement|string|Model|null
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function _match_detail_info($match_detail_id)
    {
        $data = Db::table('up__match_detail d')
            ->join('up_match_group g', 'g.mg_id=d.level_id', 'LEFT')
            ->join('up_setsail_flag f', 'f.sf_id=d.flag_start_id_bak', 'LEFT')
            ->join('up_match_sail_image i', 'i.msi_id=d.msi_id', 'LEFT')
            ->join('up_flag_signal s', 's.fs_id=d.flag_signal_id', 'LEFT')
            ->where(['id' => $match_detail_id])
            ->field('d.turn,d.level_id,g.mg_name,e_fence,f.sf_id,
                f.sf_name,f.sf_image,i.msi_id,i.msi_name,i.msi_image,i.msi_raobiao,
                i.msi_biao_name,s.fs_id,s.fs_name,s.fs_image,d.start_time,d.end_time,d.match_id,d.id,d.flag')->find();
        $data['line'] = Db::table('up__match_line')->where('match_detail_id',$match_detail_id)->select();
        return $data;
    }

    /**
     * 结束当前轮次
     * @param $match_detail_id 赛次id
     */
    public function endTurns()
    {
        $data['match_detail_id'] = input('match_detail_id');
        if (!$data['match_detail_id']) {
            return json(array('status' => 100, 'msg' => "参数不能为空"));
        }
        $end_time = microtime(true);
        $match_details = Db::table('up__match_detail')->where(['id' => $data['match_detail_id']])->update(['flag' => 2, 'end_time' => $end_time]);
        return json(array('status' => 200, 'msg' => "success",'data'=>$end_time));
    }

    /**
     * 定时计算比赛信息
     * @param $match_detail_id 赛次id
     */
    public function calculateDatas($match_detail_id)
    {

        if (!$match_detail_id) {
            return json(array('status' => 100, 'msg' => "赛次id不能为空"));
        }
        if (count($this->temp_record) < 1) {
            $boat_arr = Db::table('up__sensor_device')
                ->where('sensor_id', 'like', 'boat_%')
                ->where(['match_detail_id' => $match_detail_id])->column('sensor_id');
            $this->record_table($match_detail_id, $boat_arr);
        }
        Log::error('===================temp_record'.json_encode($this->temp_record));
        Log::error('===================开始计算');
        //获取所有设备绑定关系
        $sensor_id_arr = json_decode($this->redis->get('sensor_id_arr'), true);
        //$sensor_id_arr = Db::table('up__sensor_device')->where('match_detail_id', $match_detail_id)->column('sensor_id');
        //如果第一次计算，则初始化坐标点坐标数组
        if ($this->temp_location_data == []) {
            foreach ($sensor_id_arr as $k => $v) {
                $this->temp_location_data = array_merge($this->temp_location_data, [$v => ['sensor_id' => $v, 'lat' => '', 'lon' => '']]);
            }
        }

        //快照时间点
        $time = time();
        //$this->time_now     = $time;
        $time_pre           = $time - 2;
        $map['create_time'] = ['>', $time_pre];
        $map['create_time'] = ['<=', $time];
//        $origin_data        = Db::table('up__match_origin')
//            ->distinct('sensor_id')
//            ->where('create_time', '>', $time_pre)
//            ->where('create_time', '<=', $time)
//            ->order('id desc')
//            ->column('sensor_id,lat,lon', 'sensor_id');

        //更新起航旗
        $redis_m_d = $this->redis->get('m_d_info_' . $match_detail_id);
        if ($redis_m_d) {
            $this->match_flag_id = $redis_m_d['flag_start_id_bak'];
        }

        $data_boat   = [];
        $data_sensor = [];
        //更新各个点和船只坐标缓存
        foreach ($sensor_id_arr as $k => $v) {
            if (strstr($v, 'boat_')) {
                $data_boat[$v] = $this->temp_location_data[$v] = json_decode($this->redis->get($v), true);
            } else {
                $data_sensor[$v] = $this->temp_location_data[$v] = json_decode($this->redis->get($v), true);
                if ($data_sensor[$v]['lat'] != '' && $data_sensor[$v]['lon'] != '') {
                    //Db::table('up__match_line')->where(['match_detail_id' => $match_detail_id, 'start_sensor_id' => $v])->update(['start_lat' => $origin_data[$v]['lat'], 'start_lon' => $origin_data[$v]['lon']]);
                    //Db::table('up__match_line')->where(['match_detail_id' => $match_detail_id, 'end_sensor_id' => $v])->update(['end_lat' => $origin_data[$v]['lat'], 'end_lon' => $origin_data[$v]['lon']]);
                    //更新目标点数据
                    foreach ($this->temp_lines as $key => $value) {
                        if ($value['sensor1_id'] == $v) {
                            $this->temp_lines[$key]['lat1']       = $data_sensor[$v]['lat'];
                            $this->temp_lines[$key]['lon1']       = $data_sensor[$v]['lon'];
                            $this->temp_lines_idkey[$value['id']] = $this->temp_lines[$key];
                        }
                        if ($value['sensor2_id'] == $v) {
                            $this->temp_lines[$key]['lat2']       = $data_sensor[$v]['lat'];
                            $this->temp_lines[$key]['lon2']       = $data_sensor[$v]['lon'];
                            $this->temp_lines_idkey[$value['id']] = $this->temp_lines[$key];
                        }
                    }
                }
            }
        }
        $step_data = array_merge($data_boat, $data_sensor);
        Log::error('===================生成位置数据');
        //生成快照
        Db::table('up__match_step')->insert([
            'match_detail_id' => $match_detail_id,
            'time'            => $time,
            'data'            => json_encode($step_data)
        ]);
        //船只数据组，用于最后计算数据存放
        ///$boat_to_calculate = $step_data[1];
        //获取船只上一时刻和现在时刻的位置快照
        if ($this->temp_location_data_last == []) {
            $this->temp_location_data_last = $this->temp_location_data;
        }

        Log::error('===================temp_record2'.json_encode($this->temp_record));
        //开始循环计算
        $data_temp_to_update = [];//待更新数组
        Log::error("==========================开始循环计算");
        foreach ($this->temp_location_data as $k => $v) {
            //如果不是船不须计算
            if (!strstr($k, 'boat_')) {
                continue;
            }

            /*public $p_flag_id = 2;//p旗id
            public $i_flag_id = 3;//i旗id
            public $u_flag_id = 4;//u旗id
            public $b_flag_id = 5;//黑旗id
            public $z_flag_id = 6;//z旗id*/
            //之前黑旗犯规的不计算
            if ($this->temp_record[$v['sensor_id']]['black_rules_flag'] == 0) {
                /*if ($this->temp_record[$v['sensor_id']]['type'] != '3') {
                    $this->temp_record[$v['sensor_id']]['speed'] = $this->getSpeed($this->temp_location_data[$k], $this->temp_location_data_last[$k]);
                }*/
                //计算速度
                $this->temp_record[$v['sensor_id']]['speed']        = $this->getSpeed($this->temp_location_data[$k], $this->temp_location_data_last[$k]);
                $this->temp_record[$v['sensor_id']]['isoparmspeed'] = $this->temp_record[$v['sensor_id']]['speed'];


                //计算
                if ($time < $this->temp_one_time) {
                    //倒计时5-1
                    //  1.94386 * abs($this->temp_record[$v['sensor_id']]['black_rules_flag'];

                } elseif ($time >= $this->temp_one_time && $time < $this->temp_zero_time) {
                    //倒计时1-0
                    //黑u旗
                    if ($this->match_flag_id == $this->u_flag_id || $this->match_flag_id == $this->b_flag_id) {
                        //判断是否违规
                        if ($this->judgeRules($this->temp_location_data[$k]) == 1) {
                            Log::error('===================黑u旗犯规' . json_encode($v));
                            $this->temp_record[$v['sensor_id']]['ranking']    = $this->temp_boat_count + 1;
                            $this->temp_record[$v['sensor_id']]['rules_flag'] = $this->match_flag_id;
                            $this->temp_record[$v['sensor_id']]['temp_score'] = $this->temp_boat_count + 1;
                            if ($this->match_flag_id == $this->b_flag_id) {
                                $this->temp_record[$v['sensor_id']]['black_rules_flag'] = $this->match_flag_id;
                            }
                        }
                    } elseif ($this->match_flag_id == $this->p_flag_id) {
                        //p旗
                        if ($this->judgeRules($this->temp_location_data[$k]) == 1) {
                            Log::error('===================p旗犯规' . json_encode($v));
                            $this->temp_record[$v['sensor_id']]['ranking']    = $this->temp_boat_count + 1;
                            $this->temp_record[$v['sensor_id']]['rules_flag'] = $this->match_flag_id;
                            $this->temp_record[$v['sensor_id']]['temp_score'] = $this->temp_boat_count + 1;
                        } elseif ($this->temp_record_last[$v['sensor_id']]['rules_flag'] != 0) {
                            Log::error('===================p旗取消 犯规' . json_encode($v));
                            $this->temp_record[$v['sensor_id']]['rules_flag'] = 0;
                        } else {
                            $this->temp_record[$v['sensor_id']]['rules_flag'] = 0;
                        }
                    } elseif ($this->match_flag_id == $this->i_flag_id) {
                        //i旗
                        if ($this->judgeRules($this->temp_location_data[$k]) == 1) {
                            Log::error('===================i旗犯规' . json_encode($v));
                            $this->temp_record[$v['sensor_id']]['ranking']    = $this->temp_boat_count + 1;
                            $this->temp_record[$v['sensor_id']]['rules_flag'] = $this->match_flag_id;
                            $this->temp_record[$v['sensor_id']]['temp_score'] = $this->temp_boat_count + 1;
                        } elseif ($this->temp_record_last[$v['sensor_id']]['rules_flag'] != 0) {
                            $start_points = ['lat' => $this->temp_lines[0]['lat1'], 'lon' => $this->temp_lines[0]['lon1']];
                            $end_points   = ['lat' => $this->temp_lines[0]['lat2'], 'lon' => $this->temp_lines[0]['lon2']];
                            $inline       = $this->judgeInLine($start_points, $end_points, $this->temp_location_data[$k], $this->temp_location_data_last[$k], 3);
                            if (!$inline) {
                                $this->temp_record[$v['sensor_id']]['rules_flag'] = 0;
                            }
                        } else {
                            $this->temp_record[$v['sensor_id']]['rules_flag'] = 0;
                        }
                    } else {
                        $i = 1;
                    }
                } else {
                    $r_flag = 0;
                    //只计算没有犯规的
                    if ($this->temp_record_last[$v['sensor_id']]['rules_flag'] == 0) {
                        $r_flag = 1;
                    } else {
                        //所有犯规的
                        if ($this->match_flag_id == $this->p_flag_id) {
                            //p旗
                            if ($this->judgeRules($this->temp_location_data[$k]) == 1) {
                                Log::error('===================p旗犯规' . json_encode($v));
                                $this->temp_record[$v['sensor_id']]['ranking']    = $this->temp_boat_count + 1;
                                $this->temp_record[$v['sensor_id']]['rules_flag'] = $this->match_flag_id;
                                $this->temp_record[$v['sensor_id']]['temp_score'] = $this->temp_boat_count + 1;
                            } else {
                                $r_flag = 1;
                                Log::error('===================p旗取消 犯规' . json_encode($v));
                                $this->temp_record[$v['sensor_id']]['rules_flag'] = 0;
                            }
                        } elseif ($this->match_flag_id == $this->i_flag_id) {
                            //i旗
                            if ($this->judgeRules($this->temp_location_data[$k]) == 1) {
                                Log::error('===================i旗犯规' . json_encode($v));
                                $this->temp_record[$v['sensor_id']]['ranking']    = $this->temp_boat_count + 1;
                                $this->temp_record[$v['sensor_id']]['rules_flag'] = $this->match_flag_id;
                                $this->temp_record[$v['sensor_id']]['temp_score'] = $this->temp_boat_count + 1;
                            } else {
                                $start_points = ['lat' => $this->temp_lines[0]['lat1'], 'lon' => $this->temp_lines[0]['lon1']];
                                $end_points   = ['lat' => $this->temp_lines[0]['lat2'], 'lon' => $this->temp_lines[0]['lon2']];
                                $inline       = $this->judgeInLine($start_points, $end_points, $this->temp_location_data[$k], $this->temp_location_data_last[$k], 3);
                                if (!$inline) {
                                    $r_flag                                           = 1;
                                    $this->temp_record[$v['sensor_id']]['rules_flag'] = 0;
                                }
                            }
                        }
                    }
                    if ($r_flag == 1) {
                        $record_id = $this->getLine($this->temp_location_data[$k], $this->temp_location_data_last[$k], $time);
                        //如果i、p旗，且未在0-4分钟穿过启航线
                        if ($time > $this->temp_four_time && ($this->match_flag_id == $this->p_flag_id || $this->match_flag_id == $this->i_flag_id)) {
                            //如果未穿过启航线，则
                            if ($this->temp_record[$v['sensor_id']]['line_id'] == $this->temp_lines[0]['id']) {
                                Log::error($v['sensor_id'] . '未穿过启航线' . json_encode($v));
                                $this->temp_record[$v['sensor_id']]['ranking']    = $this->temp_boat_count + 1;
                                $this->temp_record[$v['sensor_id']]['rules_flag'] = 7;
                                $this->temp_record[$v['sensor_id']]['temp_score'] = $this->temp_boat_count + 1;
                            }
                        }
                    }
                }
            }
        }
        Log::error('===================循环更新到record表');
        //循环更新到record表
        foreach ($this->temp_record as $k => $v) {
            Db::table('up__match_arrive_record')->where('id', $v['id'])->update($v);
        }
        //获取比赛排名
        $data_rank_temp = [];
        $match_rank     = Db::table('up__match_arrive_record')->where([
            'match_detail_id' => $match_detail_id,
            'type'            => 3,
            'rules_flag'      => 0
        ])->order('time asc')->select();
        //先计算完成比赛的排序
        foreach ($match_rank as $k => $v) {
            $this->temp_record[$v['sensor_id']]['ranking']    = $k + 1;
            $this->temp_record[$v['sensor_id']]['temp_score'] = $k + 1;
            if ($k == 0) {
                $this->temp_record[$v['sensor_id']]['pre_record_sonsor'] = '';
            } else {
                $this->temp_record[$v['sensor_id']]['pre_record_sonsor'] = $match_rank[$k - 1]['sensor_id'];
            }
        }
        $next_rank   = count($match_rank) + 1;
        $match_rank2 = Db::table('up__match_arrive_record')
            ->where(['match_detail_id' => $match_detail_id])
            ->where('type', '<>', '3')
            ->where('rules_flag', '=', '0')
            ->order('line_id desc,distance asc')->select();
        foreach ($match_rank2 as $k => $v) {
            $this->temp_record[$v['sensor_id']]['ranking']    = $next_rank;
            $this->temp_record[$v['sensor_id']]['temp_score'] = $next_rank;
            //计算该船的前面一条船
            if ($k == 0) {
                if ($next_rank == 1) {
                    //这个存放这条船之前船的sensorid；
                    $this->temp_record[$v['sensor_id']]['pre_record_sonsor'] = '';
                } else {
                    $arr                                                     = array_pop($match_rank);
                    $this->temp_record[$v['sensor_id']]['pre_record_sonsor'] = $arr['sensor_id'];
                }
            } else {
                $this->temp_record[$v['sensor_id']]['pre_record_sonsor'] = $match_rank2[$k - 1]['sensor_id'];
            }
            $next_rank++;
        }
        //计算距终点距离，
        $first_boat_to_final = 0;
        $first_boat_line_id = 0;//第一条船所属赛段
        foreach ($this->temp_record as $k => $v) {
            if ($this->temp_record[$k]['rules_flag'] != 0) {
                continue;
            }
            $to_final = 0;
            foreach ($this->temp_lines_idkey as $m => $n) {
                if ($v['line_id'] < $m) {
                    $to_final += $n['distance'];
                }
            }
            $to_final                                   += $this->temp_record[$k]['distance'];
            $this->temp_record[$k]['to_final_distance'] = $to_final;
            if ($this->temp_record[$k]['ranking'] == 1) {
                $first_boat_line_id = $v['line_id'];
                $first_boat_to_final = $this->temp_record[$k]['to_final_distance'];
            }
        }
        Log::error('===================计算距终点距离');
        //距第一名距离，和前一名距离并循环更新到record表
        foreach ($this->temp_record as $k => $v) {
            if ($this->temp_record[$k]['rules_flag'] != 0) {
                continue;
            }
            if ($v['ranking'] == 1) {
                $this->temp_record[$k]['to_first_distance'] = 0;
                $this->temp_record[$k]['to_prior_distance'] = 0;
            } else {
                $to_final_distance_                         = $this->temp_record[$k]['to_final_distance'] - $first_boat_to_final;
                $this->temp_record[$k]['to_first_distance'] = number_format($to_final_distance_, 2);
                $prior_id                                   = $this->temp_record[$k]['pre_record_sonsor'];
                $this->temp_record[$k]['to_prior_distance'] = $this->temp_record[$k]['to_final_distance'] - $this->temp_record[$prior_id]['to_final_distance'];
                if($this->temp_record[$k]['to_first_distance']<0){
                    $this->temp_record[$k]['to_first_distance'] = $this->temp_record[$k]['distance'];
                }
                if($this->temp_record[$k]['to_prior_distance']<0){
                    $this->temp_record[$k]['to_prior_distance'] = $this->temp_record[$k]['distance'];
                }
            }
            unset($this->temp_record[$k]['pre_record_sonsor']);
            //unset($this->temp_record[$k]['to_final_distance']);
            Db::table('up__match_arrive_record')->where('id', $v['id'])->update($this->temp_record[$k]);
        }
        //$step_data[1] = $boat_to_calculate;
        $result = Db::table('up__match_arrive_record')
            ->where('match_detail_id', $match_detail_id)->field('sensor_id as device_id,
            speed,time,user_id,user_username,ma_fan_code,club_image,club_name,
        distance,next_points_lat,next_points_lon,type,ranking,line_id,lat,
        lon,isoparmspeed,to_final_distance,to_first_distance,to_prior_distance,
        to_start_distance,start_line_time,start_line_location,start_line_speed,to_start_angle,angle,
        rules_flag')
            ->select();
        //生成数据快照
        Db::table('up__match_datas')->insert([
            'match_detail_id' => $match_detail_id,
            'time'            => $time,
            'data'            => json_encode($result)
        ]);

        $this->redis->set('up__match_datas', json_encode($result));
        $this->temp_record_last        = $this->temp_record;
        $this->temp_location_data_last = $this->temp_location_data;

        //终点时限/1标封闭时限/过启航线最晚时间
        if (($time >= $this->match_zhong_limit && ($this->match_zhong_flag == 0)) ||
            ($time >= $this->match_first_feng_limit && ($this->match_first_feng_flag == 0))
            || ($time >= $this->match_start_limit && ($this->match_start_flag == 0))
        ) {
            Log::error('===================异常'.__LINE__);
            $match_details = Db::table('up__match_detail')->where(['id' => $match_detail_id])->update(['flag' => 2, 'end_time' => microtime(true)]);
        }
        //封闭时限
        if ($time >= $this->match_feng_limit_time && ($this->match_feng_limit_time != 0)) {

            foreach ($this->temp_record as $key => $value) {
                if ($value['type'] != 3) {
                    Log::error('===============没有在封闭时间到达的人违规有：' . json_encode($value));
                    $this->temp_record[$key]['ranking']    = $this->temp_boat_count + 1;
                    $this->temp_record[$key]['temp_score'] = $this->temp_boat_count + 1;
                }
            }
            Log::error('===================异常'.__LINE__);
            $match_details = Db::table('up__match_detail')->where(['id' => $match_detail_id])->update(['flag' => 3, 'end_time' => microtime(true)]);
        }
        //除了犯规的都到达终点
        $flag            = 1;
        $break_rules_num = 0;
        foreach ($this->temp_record as $key => $value) {
            if ($value['type'] != 3 && $this->temp_record[$key]['rules_flag'] == 0) {
                $flag = 0;
            }
            if ($this->temp_record[$key]['rules_flag'] != 0) {
                $break_rules_num++;
            }
        }
        if ($flag == 1&&$time > $this->temp_zero_time) {
            $all      = count($this->temp_record);
            $end_flag = 3;
            if ($all == $break_rules_num) {
                $end_flag = 2;
            }
            Log::error('===================异常'.__LINE__);
            $match_details = Db::table('up__match_detail')->where(['id' => $match_detail_id])->update(['flag' => $end_flag, 'end_time' => microtime(true)]);
        }
        Log::error('===================本轮计算结束');

    }

    /**
     * 判断当前船只所处赛段
     * @param $sensor_location_now 当前船只位置
     * @param $sensor_location 获取船只上一时刻位置
     * @param $time时间
     */

    public function getLine($sensor_location_now, $sensor_location, $time)
    {
        $sensor_id = $sensor_location_now['sensor_id'];
        //获取上个快照时间该船的赛段信息
        $boat_line_record = $this->temp_record_last[$sensor_id];
        $record_id        = '';

        if ($boat_line_record['type'] == 3) {
            //如果已经完成比赛，则不进行任何计算
            return $boat_line_record['line_id'];
        } else {
            //之前所在赛段信息
            $line_pre = $this->temp_lines_idkey[$boat_line_record['line_id']];
            //起始点经纬度
            $start_points = ['lat' => $line_pre['lat1'], 'lon' => $line_pre['lon1']];
            $end_points   = ['lat' => $line_pre['lat2'], 'lon' => $line_pre['lon2']];
            //获取新的目标赛段
            $line_now = $this->setLine($start_points, $end_points, $sensor_location_now, $sensor_location, $line_pre, $boat_line_record);
            //更新record表
            if ($line_now['type'] == 3) {
                $this->temp_record[$sensor_id]['distance']          = 0;
                $this->temp_record[$sensor_id]['type']              = $line_now['type'];
                $this->temp_record[$sensor_id]['line_id']           = $line_now['line']['id'];
                $this->temp_record[$sensor_id]['type']              = 3;
                $this->temp_record[$sensor_id]['time']              = $time;
                $this->temp_record[$sensor_id]['to_final_distance'] = 0;
                $this->temp_record[$sensor_id]['to_first_distance'] = 0;
                //有船到达终点
                $this->match_zhong_flag = 1;
                //如果是第一条船则，赋值封闭时限
                if ($this->match_feng_limit_time == 0) {
                    $this->match_feng_limit_time = $time + $this->match_feng_limit;
                }
            } else {
                if ($line_now['line']['id'] == $this->temp_lines[1]['id']) {
                    $this->match_start_flag = 1;
                }
                if ($line_now['line']['id'] == $this->temp_lines[2]['id']) {
                    $this->match_first_feng_flag = 1;
                }

                //新起始点经纬度
                $start_points_new = ['lat' => $line_now['line']['lat1'], 'lon' => $line_now['line']['lon1']];
                $end_points_new   = ['lat' => $line_now['line']['lat2'], 'lon' => $line_now['line']['lon2']];
                //初始起始点位置
                $start_line_points = ['lat' => $this->temp_lines[0]['lat1'], 'lon' => $this->temp_lines[0]['lon1']];
                $end_line_points   = ['lat' => $this->temp_lines[0]['lat2'], 'lon' => $this->temp_lines[0]['lon2']];

                $this->temp_record[$sensor_id]['line_id'] = $line_now['line']['id'];
                //$this->temp_record[$sensor_id]['next_points_id'] = $line_now['line']['end_sensor_id'];
                if ($line_now['line']['lat2']) {
                    $end_points_new = $end_points_new;
                }
                $next_points                                      = $this->getMiddlePoint($start_points_new, $end_points_new);
                $this->temp_record[$sensor_id]['next_points_lat'] = $next_points['lat'];
                $this->temp_record[$sensor_id]['next_points_lon'] = $next_points['lon'];
                $this->temp_record[$sensor_id]['type']            = $line_now['type'];
                $this->temp_record[$sensor_id]['rule_type']       = $line_now['line']['rule_type'];

                //求距下一个目标点距离和距起始线距离
                //获得距下一个目标点距离和更新下一个目标坐标
                $distance_middle                                    = $this->getDistanceAndMiddle($line_now['line'], $sensor_location_now);
                $this->temp_record[$sensor_id]['distance']          = $distance_middle['distance'];
                $this->temp_record[$sensor_id]['next_points_lat']   = $distance_middle['next_points']['lat'];
                $this->temp_record[$sensor_id]['next_points_lon']   = $distance_middle['next_points']['lon'];
                $this->temp_record[$sensor_id]['to_start_distance'] = $distance_middle['to_start_distance'];


//                'angle'               => 0,
//                'start_line_time'     => 0,
//                'start_line_location' => 0,
//                'start_line_speed'    => 0,
                //    private $temp_start_time = 0;//比赛开始倒计时时间
                //    private $temp_one_time = 0;//比赛开始倒计时到1分钟时间
                //    private $temp_zero_time = 0;//比赛倒计时为0时间

                if ($time > $this->temp_zero_time) {
                    //判断是否是起始赛段
                    $pre_pre_line_id = $boat_line_record['line_id'] - 1;
                    if ($line_now['line']['id'] != $line_pre['id'] && !array_key_exists($pre_pre_line_id, $this->temp_lines_idkey)) {
                        //计算角度
                        $this->temp_record[$sensor_id]['to_start_angle'] = $this->getAngle($sensor_location_now, $sensor_location, $start_points, $end_points);
                        //计算距开始比赛时间
                        $to_start_time_                                   = $time - $this->temp_zero_time;
                        $this->temp_record[$sensor_id]['start_line_time'] = number_format((float)$to_start_time_, 2);
                        //计算速度
                        $this->temp_record[$sensor_id]['start_line_speed'] = $this->getSpeed($sensor_location_now, $sensor_location);
                        //计算交点位置
                        $this->temp_record[$sensor_id]['start_line_location'] = $this->getLocation($start_points, $end_points);
                    }
                }
                //计算船与正北夹角
                $this->temp_record[$sensor_id]['angle'] = $this->getNorthAngle($sensor_location_now, $distance_middle['next_points']);
                //计算等位线速度(只计算两秒内没有切换赛段的)
                if ($line_now['line']['id'] == $line_pre['id']) {
                    $speed                                         = 1.94386 * abs($this->temp_record_last[$sensor_id]['distance'] - $this->temp_record[$sensor_id]['distance']);
                    $speed                                         = number_format($speed, 2);
                    $this->temp_record[$sensor_id]['isoparmspeed'] = $speed;
                } else {
                    $this->temp_record[$sensor_id]['isoparmspeed'] = $boat_line_record['isoparmspeed'];
                }
            }

            return $boat_line_record['id'];
        }
    }

    //计算等位线速度
    public function getIsoparmSpeed($disrtance_pre, $distance)
    {
        return ((float)$disrtance_pre - (float)$distance) / 1;
    }

    //求当前船的速度
    public function getSpeed($location, $location_last)
    {
        $distance = $this->getDistance($location_last, $location);
        $speed    = 1.94386 * abs((float)$distance / 1);
        $speed    = number_format($speed, 2);
        return $speed;
    }

    //判断船所处象限
    function get_quadrant($boat, $target)
    {
        //1-在第一象限，2-在第二象限，3-在第三象限，4-在第四象限，5-不在探测范围
        if (($boat['lat'] > $target['lat']) && ($boat['lon'] > $target['lon'])) {
            return 1;
        } else if (($boat['lon'] <= $target['lon']) && ($boat['lat'] > $target['lat'])) {
            return 2;
        } else if (($boat['lat'] <= $target['lat']) && ($boat['lon'] <= $target['lon'])) {
            return 3;
        } else {
            return 4;
        }
    }

    /**
     * 求船与正北角度
     * @param $sensor_location_now 船现在位置
     * @param $sensor_location 船之前位置
     */
    public function getNorthAngle($sensor_location_now, $middle_points)
    {
        $params_boat = $this->getLineFunction($sensor_location_now, $middle_points);
        if ($params_boat['flag'] == 1) {
            return atan(abs($params_boat['k'])) / pi() * 180;
        } elseif ($params_boat['flag'] == 2) {
            return 0;
        } else {
            return 90;
        }
    }

    /**
 * 求船角度
 * @param $sensor_location_now 船现在位置
 * @param $sensor_location 船之前位置
 * @param $start_points 船现在位置
 * @param $end_points 船之前位置
 */
    public function getAngle($sensor_location_now, $sensor_location, $start_points, $end_points)
    {
        //先计算船直线和启航线直线
        $params_boat     = $this->getLineFunction($sensor_location_now, $sensor_location);
        $params          = $this->getLineFunction($start_points, $end_points);
        $crossover_point = [];
        //求角度
        $to_start_angle = '';
        //flag 1 ,正常直线  2垂直于y轴  3垂直于x轴
        //tanα   =|(k2 - k1) / (1 + k1k2) |
        if ($params['flag'] == 1) {
            if ($params_boat['flag'] == 1) {
                $to_start_angle = 90 - atan(abs(($params_boat['k'] - $params['k']) / (1 + $params_boat['k'] * $params['k']))) / pi() * 180;
            } elseif ($params_boat['flag'] == 2) {
                $to_start_angle = 90 - atan(abs($params['k'])) / pi() * 180;
            } else {
                $to_start_angle = 90 - atan(abs($params['k'])) / pi() * 180;
            }
        } elseif ($params['flag'] == 2) {
            if ($params_boat['flag'] == 1) {
                $to_start_angle = 90 - atan(abs($params_boat['k'])) / pi() * 180;
            } else {
                $to_start_angle = 90;
            }
        } else {
            if ($params_boat['flag'] == 1) {
                $to_start_angle = 90 - atan(abs($params_boat['k'])) / pi() * 180;
            } else {
                $to_start_angle = 90;
            }
        }
        $to_start_angle = number_format((float)$to_start_angle, 2);
        //起始点在1 3 象限则右
        if ($sensor_location['lat'] < $this->temp_start_cross_points['lat'] && $sensor_location['lon'] < $this->temp_start_cross_points['lon']
            || $sensor_location['lat'] > $this->temp_start_cross_points['lat'] && $sensor_location['lon'] > $this->temp_start_cross_points['lon']
        ) {
            return -$to_start_angle;
        } else {
            return $to_start_angle;
        }
    }

    /**
     * 求船在经过起始线时在线段的位置
     * @param $start_points 启航线起始点
     * @param $end_points 启航线zhongdian
     */
    public function getLocation($start_points, $end_points)
    {
        //启航线长度
        $line_distance = $this->getDistance($start_points, $end_points);
        //交点到启航线左点长度
        $cross_distance = $this->getDistance($start_points, $this->temp_start_cross_points);
        $half           = $line_distance / 2;
        $D_value        = $cross_distance - $half;
        $abs            = abs($D_value);
        if ($D_value > 0) {
            return 'R' . round($abs / $half * 100) . "%";
        } else {
            return 'L' . round($abs / $half * 100) . "%";
        }
    }

    /**
     * 获取当前赛段信息
     * @param $start_points 开始点
     * @param $end_points 结束点
     * @param $sensor_location 上次位置
     * @param $sensor_location_now 此时位置
     * @param $boat_line_record 上次船只到达记录
     */
    public function setLine($start_points, $end_points, $sensor_location_now, $sensor_location, $line_pre, $boat_line_record)
    {
        $flag = 1;
        //$flag    = $this->triggerDetection( $end_points, $sensor_location_now,$line_pre);
        if ($flag == 1) {//进入检测区域
            $res = $this->line_rules($start_points, $end_points, $sensor_location_now, $sensor_location, $line_pre, $boat_line_record);
            if ($res) {//检测通过
                if ($line_pre['rule_type'] == 2) {
                    return ['line' => $line_pre, 'type' => 3];
                } else {
                    $line_next_id = $line_pre['id'] + 1;
                    $line         = $this->temp_lines_idkey[$line_next_id];
                    return ['line' => $line, 'type' => 1];
                }
            } else {
                return ['line' => $line_pre, 'type' => 2];
            }
        } else {
            return ['line' => $line_pre, 'type' => 1];
        }
    }

    /**
     * 判断是否触发检测
     * @param $end_points
     * @param $sensor_location_now
     * @param $line_pre
     */
    public function triggerDetection($end_points, $sensor_location_now, $line_pre)
    {
        $flag = 0;//0未触发1已触发
        $type = $line_pre['rule_type'];
        if ($type == 1 || $type == 2) {
            $flag = 1;
        } elseif ($type == 3 || $type == 4) {
            $scope    = $this->getScope($line_pre);//获得监测范围
            $distance = $this->getDistance($end_points, $sensor_location_now);
            if ($distance < $scope) {
                $flag = 1;
            }
        } else {
            $flag = 0;
        }
        return $flag;
    }

    /**
     * 查询检测范围
     * @param $line
     */
    public function getScope($line)
    {
        return $this->scope;
    }

    /**
     * 判断是否经过点
     * @param $start_points 开始点
     * @param $end_points 结束点
     * @param $sensor_location 上次位置
     * @param $sensor_location_now 此时位置
     * @param $boat_line_record 船记录
     */
    public function line_rules($start_points, $end_points, $sensor_location_now, $sensor_location, $line_pre, $boat_line_record)
    {
        $type      = $line_pre['rule_type'];
        $sensor_id = $sensor_location_now['sensor_id'];
        if ($type == 1 || $type == 2 || $type == 3) {
            $start_points = ['lat' => $line_pre['lat1'], 'lon' => $line_pre['lon1']];
            $end_points   = ['lat' => $line_pre['lat2'], 'lon' => $line_pre['lon2']];
            return $this->judgeInLine($start_points, $end_points, $sensor_location_now, $sensor_location, $type);
        } else {
            //要达到的象限列表
            $quadrant_list = [];
            //需要经过几个象限组成的字符串长度
            $quadrant_all = 5;
            if ($type == 4 || $type == 6) {
                $quadrant_list = ['1,2,3,4', '1,2,3,4', '3,4,1,2', '4,1,2,3'];
                $quadrant_all  = 7;
            } elseif ($type == 7) {
                $quadrant_list = ['2,3,4', '1,2,3', '3,4,1', '4,1,2'];
            } elseif ($type == 8) {
                $quadrant_list = ['4,3,2,1', '3,2,1,4', '2,1,4,3', '1,4,3,2'];
                $quadrant_all  = 7;
            } else {
                //type == 9
                $quadrant_list = ['4,3,2', '3,2,1', '2,1,4', '1,4,3'];
            }
            $end_points = ['lat' => $line_pre['lat1'], 'lon' => $line_pre['lon1']];
            //获得所在象限
            if (!$boat_line_record['complete_quadrants']) {
                $quadrant = $this->get_quadrant($sensor_location_now, $end_points);
                //之前没有到达象限记录
                foreach ($quadrant_list as $k => $v) {
                    if (substr($v, 0, 1) == $quadrant) {
                        $quadrant_arr = explode(',', $v);
                        //更新新的象限到record表
                        $this->temp_record[$sensor_id]['next_quadrant']      = $quadrant_arr[1];
                        $this->temp_record[$sensor_id]['complete_quadrants'] = $quadrant;
                    }
                }
                return 0;
            } else {
                if ($type == 4 && strlen($boat_line_record['complete_quadrants']) >= 3) {
                    $end_points = ['lat' => $line_pre['lat2'], 'lon' => $line_pre['lon2']];
                }
                $quadrant = $this->get_quadrant($sensor_location_now, $end_points);
                //之前有到达象限记录
                if ($quadrant == $boat_line_record['next_quadrant']) {
                    $quadrant_str = $boat_line_record['complete_quadrants'] . ',' . $quadrant;
                    $quadrant_len = strlen($quadrant_str);
                    if ($quadrant_len == $quadrant_all) {
                        //更新新的象限到record表
                        $this->temp_record[$sensor_id]['next_quadrant']      = '';
                        $this->temp_record[$sensor_id]['complete_quadrants'] = '';
                        //长度想等说明已经经过要经过的全部象限
                        return 1;
                    } else {
                        foreach ($quadrant_list as $k => $v) {
                            if (substr($v, 0, $quadrant_len) == $quadrant_str) {
                                $quadrant_arr = explode(',', $v);
                                //更新新的象限到record表
                                $this->temp_record[$sensor_id]['next_quadrant']      = substr(str_replace($quadrant_str . ",", '', $v), 0, 1);
                                $this->temp_record[$sensor_id]['complete_quadrants'] = $quadrant_str;
                            }
                        }
                        return 0;
                    }
                } else {
                    return 0;
                }
            }
        }
    }

    /**
     * 判断是否相交，并且在线段上
     * @param $start_points 起始坐标
     * @param $end_points  中点坐标
     * @param $sensor_location_now 船当前坐标
     * @param $sensor_location 船只之前坐标
     * @param $type 要判断的线的类型 1起始线 2终止线
     */
    public function judgeInLine($start_points, $end_points, $sensor_location_now, $sensor_location, $type)
    {
        //求另一条直线
        if (!array_diff($sensor_location_now, $sensor_location) && !array_diff($sensor_location, $sensor_location_now)) {
            return 0;//未相交
        }
        if ($sensor_location_now['lon'] == $sensor_location['lon'] && $sensor_location_now['lat'] == $sensor_location['lat']) {
            return 0;//未相交
        }
        $params = $this->getLineFunction($start_points, $end_points);//求起始点终止点的直线

        $params_boat     = $this->getLineFunction($sensor_location_now, $sensor_location);//求起始点终止点的直线
        $crossover_point = [];
        //两条正常直线
        if ($params['flag'] == 1) {
            if ($params_boat['flag'] == 1) {
                $boat_k = $params_boat['k'];
                $boat_b = $params_boat['b'];
                if ($boat_k == $params['k']) {
                    return 0;//未相交
                }
                $crossover_point = $this->getCrossover(['k' => $params['k'], 'b' => $params['b']], ['k' => $boat_k, 'b' => $boat_b]);
            } elseif ($params_boat['flag'] == 2) {
                $crossover_point['lat'] = ($params_boat['b'] - $params['b']) / $params['k'];
                $crossover_point['lon'] = $params_boat['b'];
            } else {
                $crossover_point['lat'] = $params_boat['b'];
                $crossover_point['lon'] = $params_boat['b'] * $params['k'] + $params['b'];
            }
        } elseif ($params['flag'] == 2) {
            if ($params_boat['flag'] == 1) {
                $crossover_point['lat'] = ($params['b'] - $params_boat['b']) / $params_boat['k'];
                $crossover_point['lon'] = $params['b'];
            } elseif ($params_boat['flag'] == 2) {
                return 0;
            } else {
                $crossover_point['lat'] = $params_boat['b'];
                $crossover_point['lon'] = $params['b'];
            }
        } else {
            if ($params_boat['flag'] == 1) {
                $crossover_point['lat'] = $params['b'];
                $crossover_point['lon'] = $params['b'] * $params_boat['k'] + $params_boat['b'];
            } elseif ($params_boat['flag'] == 2) {
                $crossover_point['lat'] = $params['b'];
                $crossover_point['lon'] = $params_boat['b'];
            } else {
                return 0;
            }
        }

        //判断点是否在线段上
        $PAx = $start_points['lat'];
        $PAy = $start_points['lon'];
        $PBx = $end_points['lat'];
        $PBy = $end_points['lon'];
        $PCx = $sensor_location_now['lat'];
        $PCy = $sensor_location_now['lon'];
        $PDx = $sensor_location['lat'];
        $PDy = $sensor_location['lon'];
        $x   = $crossover_point['lat'];
        $y   = $crossover_point['lon'];
        if ((min($PAx, $PBx) <= $x && $x <= max($PAx, $PBx) && min($PAy, $PBy) <= $y && $y <= max($PAy, $PBy)) && (min($PCx, $PDx) <= $x && $x <= max($PCx, $PDx) && min($PCy, $PDy) <= $y && $y <= max($PCy, $PDy))) {
            if ($type == 1) {
                $this->temp_start_cross_points = $crossover_point;
            }
            return 1;//相交在线上
        } else {
            return 0;//未相交
        }
    }

    /**
     * 求等位线距离（垂直距离）
     * @param $start_points 起始坐标
     * @param $end_points  中点坐标
     * @param $sensor_location_now 船坐标
     */
    public function getIsoparmDistance($start_points, $end_points, $sensor_location_now)
    {
        $params          = $this->getLineFunction($start_points, $end_points);//求起始点终止点的直线
        $crossover_point = [];
        if ($params['flag'] == 1) {
            //求另一条直线
            $boat_k = -$params['k'];
            $boat_b = (float)$sensor_location_now['lon'] - (float)$boat_k * (float)$sensor_location_now['lat'];

            //求交点
            $crossover_point = $this->getCrossover(['k' => $params['k'], 'b' => $params['b']], ['k' => $boat_k, 'b' => $boat_b]);
        } elseif ($params['flag'] == 2) {
            $crossover_point['lat'] = (float)$sensor_location_now['lat'];
            $crossover_point['lon'] = $params['b'];
        } else {
            $crossover_point['lon'] = (float)$sensor_location_now['lat'];
            $crossover_point['lat'] = $params['b'];
        }
        //求等位线距离
        $distance = $this->getDistance($crossover_point, $end_points);
        return $distance;
    }

    /**
     * 求直线方程
     * @param $start_points 起始坐标
     * @param $end_points  中点坐标
     */
    public function getLineFunction($start_points, $end_points)
    {
        //y=$a*$x+$b
        //flag 1 ,正常直线  2垂直于y轴(lon)  3垂直于x轴(lat)
        if (((float)$start_points['lon'] - (float)$end_points['lon']) == 0) {
            return ['k' => 0, 'b' => (float)$start_points['lon'], 'flag' => 2];
        }
        if (((float)$start_points['lat'] - (float)$end_points['lat']) == 0) {
            return ['k' => 0, 'b' => (float)$start_points['lat'], 'flag' => 3];
        }
        $a = ((float)$start_points['lon'] - (float)$end_points['lon']) / ((float)$start_points['lat'] - (float)$end_points['lat']);
        $b = (float)$start_points['lon'] - $a * (float)$start_points['lat'];
        return ['k' => $a, 'b' => $b, 'flag' => 1];
    }

    /**
     * 求两直线交点
     * @param $line1 直线1参数数组
     * @param $line2  直线2参数数组
     * $line1=['k'=>1,'b'=>2]
     */
    public function getCrossover($line1, $line2)
    {
        //求交点
        $x = ($line2['b'] - $line1['b']) / ($line1['k'] - $line2['k']);
        $y = $line1['k'] * $x + $line1['b'];
        return ['lat' => $x, 'lon' => $y];
    }

    /**
     * 距离计算
     * @param $point1 浮标位置、船位置
     * @param $point2
     * $point1:[lat=>11,lon=>22]
     */
    public function getDistance($point1, $point2)
    {
        // 将角度转为弧度
        $radLat1  = deg2rad((float)$point1['lat']); //deg2rad()函数将角度转换为弧度
        $radLat2  = deg2rad((float)$point2['lat']);
        $radLng1  = deg2rad((float)$point1['lon']);
        $radLng2  = deg2rad((float)$point2['lon']);
        $a        = $radLat1 - $radLat2;
        $b        = $radLng1 - $radLng2;
        $distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6378.137 * 1000;
        return $distance;
    }


    //产生随机数
    public function getNumber($number)
    {
        extract(input());
        $device = Db::table('up__sensor')
            ->where('app_number', $number)
            ->find();
        if ($device) {
            $num = rand(1000, 9999);
            return $this->getNumber($num);
        } else {
            return $number;
        }
    }

    public function createQRcode($aid)
    {
        $dir = $_SERVER['DOCUMENT_ROOT'];
        $url = "http://" . $_SERVER['HTTP_HOST'];
        require_once VENDOR_PATH . "phpqrcode.php";
        $rand                 = date('YmdHis') . rand(100000, 999999);
        $value                = "$aid"; //二维码内容：链接
        $errorCorrectionLevel = 'L';    //容错级别
        $matrixPointSize      = 8;           //生成图片大小
        //生成二维码图片
        $ymd      = date('Ymd');
        $zip_path = "{$dir}/uploads/face/$ymd";
        //dump($zip_path);die;
        if (!file_exists($zip_path)) {
            mkdir($zip_path, 0777, true);
        }
        $filename = "$zip_path/{$rand}.png";
        $filehttp = "{$url}/uploads/face/$ymd/{$rand}.png";
        \QRcode::png($value, $filename, $errorCorrectionLevel, $matrixPointSize, 2);
        $QR = $filename;              //已经生成的原始二维码图片文件
        $QR = imagecreatefromstring(file_get_contents($QR));
        //输出图片
//        imagepng($QR, 'qrcode.png');
        imagedestroy($QR);
        return $filehttp;
    }

    /**
     * 绑定坐标
     * @param $line1 直线1参数数组
     * @param $line2  直线2参数数组
     * $line1=['k'=>1,'b'=>2]
     */
    public function bindSensor($key, $sensor_id, $m_d_id)
    {
        $res = Db::table('up__sensor')->where(['app_number' => $sensor_id])->find();
        if (!$res) {
            return array('status' => 100, 'msg' => '设备号不存在');
        }

        $sensor = Db::table('up__sensor')->where([
            'sensor_id'       => $sensor_id,
            'match_detail_id' => $m_d_id])->find();
        if ($sensor) {

        } else {
            if ($sensor['name'] == "SS" || $sensor['name'] == "SP" || $sensor['name'] == "FS" || $sensor['name'] == "FP") {
            }
            Db::table('up__sensor_device')->where([
                'name' => $key, 'match_detail_id' => $m_d_id
            ])->update(['sensor_id' => $sensor_id]);
        }
        return array('status' => 200, 'msg' => '绑定成功');
    }

    /**
     * 求中点
     * @param $point1
     * @param $point2
     */
    public function getMiddlePoint($point1, $point2)
    {
        $target['lat'] = ($point1['lat'] + $point2['lat']) / 2;
        $target['lon'] = ($point1['lon'] + $point2['lon']) / 2;
        return $target;
    }

    /**
     * 求中点之间距离
     * @param $point1
     * @param $point2
     * @param $point3
     * @param $point4
     */
    public function getMiddleDistance($point1 = [], $point2 = [], $point3 = [], $point4 = [])
    {
        $distance = 0;

        if ($point3 == []) {
            //两个点间距
            $target_last = $point1;
            $target_now  = $point2;
            $distance    = $this->getDistance($target_last, $target_now);
        } elseif ($point4 == []) {
            //前后两个目标点，一个为线，一个为点
            $target_last = $this->getMiddlePoint($point1, $point2);
            $target_now  = $point3;
            $distance    = $this->getDistance($target_last, $target_now);
        } else {
            //两个都是线
            $target_last = $this->getMiddlePoint($point1, $point2);
            $target_now  = $this->getMiddlePoint($point3, $point4);
            $distance    = $this->getDistance($target_last, $target_now);
        }
        return $distance;
    }

    /**
     * 求中点和船到目标点距离
     * @param $line 现在目标点
     * @param $sensor_location_now 船现在位置
     */
    public function getDistanceAndMiddle($line, $sensor_location_now)
    {

        //起始线坐标
        $ss_point = ['lat' => $this->temp_lines[0]['lat1'], 'lon' => $this->temp_lines[0]['lon1']];
        $sp_point = ['lat' => $this->temp_lines[0]['lat2'], 'lon' => $this->temp_lines[0]['lon2']];
        //距起始线距离
        $to_start_distance    = $this->getIsoparmDistance($ss_point, $sp_point, $sensor_location_now);
        $distance_middlepoint = [];
        if ($line['rule_type'] == 1) {
            $next_start_points                         = ['lat' => $line['lat1'], 'lon' => $line['lon1']];
            $next_end_points                           = ['lat' => $line['lat2'], 'lon' => $line['lon2']];
            $distance_middlepoint['next_points']       = $this->getMiddlePoint($next_start_points, $next_end_points);
            $distance_middlepoint['distance']          = $to_start_distance;
            $distance_middlepoint['to_start_distance'] = -$distance_middlepoint['distance'];
        } else {
            $line_next_id                              = $line['id'] - 1;
            $line_pre                                  = $this->temp_lines_idkey[$line_next_id];
            $distance_middlepoint['to_start_distance'] = $to_start_distance;
            if (($line['rule_type'] == 6 || $line['rule_type'] == 7
                    || $line['rule_type'] == 8 || $line['rule_type'] == 9
                ) && ($line_pre['rule_type'] == 6 || $line_pre['rule_type'] == 7
                    || $line_pre['rule_type'] == 8 || $line_pre['rule_type'] == 9
                )) {
                //目标点到目标点距离
                $start                               = ['lat' => $line_pre['lat1'], 'lon' => $line_pre['lon1']];
                $end                                 = ['lat' => $line['lat1'], 'lon' => $line['lon1']];
                $distance_middlepoint['next_points'] = $end;
                $distance_middlepoint['distance']    = $this->getIsoparmDistanceNew($start, $end, $sensor_location_now);

            } elseif (($line['rule_type'] == 2 || $line['rule_type'] == 3
                    || $line['rule_type'] == 4 || $line['rule_type'] == 5
                ) && ($line_pre['rule_type'] == 1 || $line_pre['rule_type'] == 3
                    || $line_pre['rule_type'] == 4 || $line_pre['rule_type'] == 5
                )) {
                //求双坐标直线，求中点到中点距离
                $last_start                          = ['lat' => $line_pre['lat1'], 'lon' => $line_pre['lon1']];
                $last_end                            = ['lat' => $line_pre['lat2'], 'lon' => $line_pre['lon2']];
                $now_start                           = ['lat' => $line['lat1'], 'lon' => $line['lon1']];
                $now_end                             = ['lat' => $line['lat2'], 'lon' => $line['lon2']];
                $distance_middlepoint['next_points'] = $this->getMiddlePoint($now_start, $now_end);
                $last_middle                         = $this->getMiddlePoint($last_start, $last_end);
                $distance_middlepoint['distance']    = $this->getIsoparmDistanceNew($last_middle, $distance_middlepoint['next_points'], $sensor_location_now);
            } elseif (($line['rule_type'] == 6 || $line['rule_type'] == 7
                    || $line['rule_type'] == 8 || $line['rule_type'] == 9
                ) && ($line_pre['rule_type'] == 1 || $line_pre['rule_type'] == 3
                    || $line_pre['rule_type'] == 4 || $line_pre['rule_type'] == 5
                )) {
                //求双坐标直线，求中点到点距离
                $last_start                          = ['lat' => $line_pre['lat1'], 'lon' => $line_pre['lon1']];
                $last_end                            = ['lat' => $line_pre['lat2'], 'lon' => $line_pre['lon2']];
                $now                                 = ['lat' => $line['lat1'], 'lon' => $line['lon1']];
                $distance_middlepoint['next_points'] = $now;
                $last_middle                         = $this->getMiddlePoint($last_start, $last_end);
                $distance_middlepoint['distance']    = $this->getIsoparmDistanceNew($last_middle, $distance_middlepoint['next_points'], $sensor_location_now);
            } else {
                //求双坐标直线，求中点到点距离
                $now_start                           = ['lat' => $line['lat1'], 'lon' => $line['lon1']];
                $now_end                             = ['lat' => $line['lat2'], 'lon' => $line['lon2']];
                $last                                = ['lat' => $line_pre['lat1'], 'lon' => $line_pre['lon1']];
                $distance_middlepoint['next_points'] = $this->getMiddlePoint($now_start, $now_end);
                $distance_middlepoint['distance']    = $this->getIsoparmDistanceNew($last, $distance_middlepoint['next_points'], $sensor_location_now);
            }
        }
        return $distance_middlepoint;
    }


    /**
     * 求等位线距离（垂直距离）新算法
     * @param $start_points 起始坐标
     * @param $end_points  终点坐标
     * @param $sensor_location_now 船坐标
     */
    public function getIsoparmDistanceNew($start_points, $end_points, $sensor_location_now)
    {
        $params          = $this->getLineFunction($start_points, $end_points);//求起始点终止点的直线
        $crossover_point = [];
        if ($params['flag'] == 1) {
            //获得船所在直线
            $boat_k = -$params['k'];
            $boat_b = (float)$sensor_location_now['lon'] - (float)$boat_k * (float)$sensor_location_now['lat'];
            //求另一条直线
            //$line_k = -$params['k'];
            //$line_b = (float)$end_points['lon'] - (float)$line_k * (float)$end_points['lat'];
            $line_k = $params['k'];
            $line_b = $params['b'];
            //求交点
            $crossover_point = $this->getCrossover(['k' => $line_k, 'b' => $line_b], ['k' => $boat_k, 'b' => $boat_b]);
        } elseif ($params['flag'] == 2) {
            $crossover_point['lat'] = (float)$end_points['lat'];
            $crossover_point['lon'] = (float)$sensor_location_now['lon'];
        } else {
            $crossover_point['lat'] = (float)$sensor_location_now['lat'];
            $crossover_point['lon'] = (float)$end_points['lon'];
        }
        //求等位线距离
        $distance = $this->getDistance($crossover_point, $end_points);
        return $distance;
    }

    /**
     * 判断船是否过期航线（1过了，-1未过）
     * @param $sensor_location_now 船坐标
     */
    public function judgeRules($sensor_location_now)
    {
        $start_points = ['lat' => $this->temp_lines[0]['lat1'], 'lon' => $this->temp_lines[0]['lon1']];
        $end_points   = ['lat' => $this->temp_lines[0]['lat2'], 'lon' => $this->temp_lines[0]['lon2']];
        Log::error('$start_points' . json_encode($start_points));
        Log::error('$end_points' . json_encode($end_points));
        //以第一个目标点为目标，求中点坐标
        $middle_points       = [];
        $middle_start_points = ['lat' => $this->temp_lines[1]['lat1'], 'lon' => $this->temp_lines[1]['lon1']];
        $middle_end_points   = ['lat' => $this->temp_lines[1]['lat2'], 'lon' => $this->temp_lines[1]['lon2']];
        if ($this->temp_lines[1]['lat2']) {

            $middle_points = $this->getMiddlePoint($middle_start_points, $middle_end_points);
        } else {
            $middle_points = $middle_start_points;
        }

        $params      = $this->getLineFunction($start_points, $end_points);//求起始点终止点的直线
        $params_boat = $this->getLineFunction($sensor_location_now, $middle_points);//求船与第一个坐标直线
        Log::error('$params' . json_encode($params));
        Log::error('$params_boat' . json_encode($params_boat));
        $crossover_point = [];
        if ($params['flag'] == 1) {
            if ($params_boat['flag'] == 1) {
                $crossover_point = $this->getCrossover(['k' => $params['k'], 'b' => $params['b']], ['k' => $params_boat['k'], 'b' => $params_boat['b']]);
            } elseif ($params_boat['flag'] == 2) {
                $crossover_point['lat'] = ((float)$params_boat['b'] - (float)$params['b']) / (float)$params['k'];
                $crossover_point['lon'] = (float)$params_boat['b'];
            } else {
                $crossover_point['lat'] = (float)$params_boat['b'];
                $crossover_point['lon'] = (float)$params['k'] * (float)$params_boat['b'] + (float)$params['b'];
            }
        } elseif ($params['flag'] == 2) {
            if ($params_boat['flag'] == 1) {
                $crossover_point['lat'] = ((float)$params['b'] - (float)$params_boat['b']) / (float)$params_boat['k'];
                $crossover_point['lon'] = (float)$params['b'];
            } elseif ($params_boat['flag'] == 2) {
                $crossover_point = [];
            } else {
                $crossover_point['lat'] = (float)$params_boat['b'];
                $crossover_point['lon'] = (float)$params['b'];
            }
        } else {
            if ($params_boat['flag'] == 1) {
                $crossover_point['lat'] = (float)$params['b'];
                $crossover_point['lon'] = (float)$params_boat['k'] * (float)$params['b'] + (float)$params_boat['b'];
            } elseif ($params_boat['flag'] == 2) {
                $crossover_point['lat'] = (float)$params['b'];
                $crossover_point['lon'] = (float)$params_boat['b'];
            } else {
                $crossover_point = [];
            }
        }
        //向量求方向
        if ($crossover_point == [] || count($crossover_point) == 0) {
            return 1;
        } else {
            /*
                向量a=(x1,y1), 向量b=(x2,y2).
                因向量dua与向量b共线，故zhi x1y2-x2y1=0, 即 x1/x2=y1/y2.
                若x1/x2=y1/y2＞0.则向量a与向量b同向共线；
                若x1/x2=y1/y2＜0,则向量a与向量b反向dao共线。
            */
            $cross_end_lat  = (float)$middle_points['lat'] - (float)$crossover_point['lat'];
            $cross_boat_lat = (float)$sensor_location_now['lat'] - (float)$crossover_point['lat'];
            $res            = 1;
            if ($cross_end_lat == $cross_boat_lat) {
                $cross_end_lon  = (float)$middle_points['lon'] - (float)$crossover_point['lon'];
                $cross_boat_lon = (float)$sensor_location_now['lon'] - (float)$crossover_point['lon'];
                if ($cross_end_lon == $cross_boat_lon) {
                    return 1;
                } else {
                    $res = $cross_end_lon / $cross_boat_lon;
                }
            } else {
                $res = $cross_end_lat / $cross_boat_lat;
            }

            if ($res > 0) {
                Log::error('+++++++++同向');
                return 1;
            } else {
                Log::error('+++++++++反向');
                return -1;
            }
        }
    }

    /**
     * 更新、上传船只设备位置
     * @param $lat
     * @param $lon
     * @param $user_id
     * @return {app_sb_id,app_id,app_number,app_ercode}
     */
    public function updAllDevive()
    {
        $dat = input('location/a');
        foreach ($dat as $k => $v) {
            if (strstr('boat', $v['sensor_id'])) {
                $data['type'] = 1;
            } else {
                $data['type'] = 2;
            }
            //$data['sensor_id'] = input('id');
            $data['sensor_id']   = $v['sensor_id'];
            $data['lat']         = $v['lat'];
            $data['lon']         = $v['lon'];
            $data['create_time'] = microtime(true);
            $this->redis->set($data['sensor_id'], json_encode($data));
            $res = Db::table('up__match_origin')->insert($data);
        }
        return json(array('status' => 200, 'msg' => "success"));
    }

    function getTimeNow(){
        return json(array('status' => 200, 'data' => microtime(true)));
    }
}